Skip to content

Commit

Permalink
refactor: unify extra service
Browse files Browse the repository at this point in the history
  • Loading branch information
xchacha20-poly1305 committed Oct 4, 2024
1 parent 37bff99 commit 3aca3f4
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 214 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ class NativeInterface : PlatformInterface {
// libbox interface

override fun autoDetectInterfaceControl(fd: Int) {
DataStore.vpnService?.protect(fd)
// Make it throw NPE
val success = DataStore.vpnService!!.protect(fd)
if (!success) error("failed to protect $fd")
}

override fun clashModeCallback(mode: String?) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ class ProxyInstance(profile: ProxyEntity, var service: BaseService.Interface? =
}

override fun launch() {
box.setAsMain()
super.launch() // start box
runOnDefaultDispatcher {
service?.let {
Expand Down
91 changes: 46 additions & 45 deletions libcore/box.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package libcore

import (
"context"
"io"
"time"

box "github.com/sagernet/sing-box"
Expand All @@ -13,6 +12,7 @@ import (
_ "github.com/sagernet/sing-box/include"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/outbound"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
Expand All @@ -39,19 +39,15 @@ const (

type BoxInstance struct {
*box.Box
forTest bool
cancel context.CancelFunc
state atomic.TypedValue[boxState]

cancel context.CancelFunc

state atomic.TypedValue[boxState]

protectFun protect.Protect
protectCloser io.Closer

selector *outbound.Selector
selectorCallback selectorCallback

// services are BoxInstance' extra services.
services []any
selector *outbound.Selector
clashModeHook chan struct{}
clashModeCallback func(mode string)
platformInterface PlatformInterface

pauseManager pause.Manager
servicePauseFields
Expand Down Expand Up @@ -99,26 +95,29 @@ func NewBoxInstance(config string, platformInterface PlatformInterface) (b *BoxI
}

b = &BoxInstance{
Box: instance,
cancel: cancel,
protectFun: func(fd int) error {
return platformInterface.AutoDetectInterfaceControl(int32(fd))
},
pauseManager: service.FromContext[pause.Manager](ctx),
Box: instance,
forTest: forTest,
cancel: cancel,
platformInterface: platformInterface,
pauseManager: service.FromContext[pause.Manager](ctx),
}

if !forTest {
// selector
if proxy, haveProxyOutbound := b.Box.Router().Outbound("proxy"); haveProxyOutbound {
if selector, isSelector := proxy.(*outbound.Selector); isSelector {
b.selector = selector
b.selectorCallback = platformInterface.SelectorCallback
}
}

// Clash
if clash := b.Box.Router().ClashServer(); clash != nil {
b.clashModeCallback = platformInterface.ClashModeCallback
// Protect
protectServer, err := protect.New(ctx, log.StdLogger(), ProtectPath, func(fd int) error {
return platformInterface.AutoDetectInterfaceControl(int32(fd))
})
if err != nil {
log.WarnContext(ctx, "create protect service: ", err)
} else {
b.services = append(b.services, protectServer)
}
}

Expand All @@ -138,14 +137,26 @@ func (b *BoxInstance) Start() (err error) {
return err
}

if b.selector != nil {
oldCancel := b.cancel
ctx, cancel := context.WithCancel(context.Background())
b.cancel = func() {
oldCancel()
cancel()
if !b.forTest {
for i, extraService := range b.services {
if starter, isStarter := extraService.(interface {
Start() error
}); isStarter {
err := starter.Start()
if err != nil {
log.Warn("starting extra service [", i, "]: ", err)
}
}
}
if b.selector != nil {
oldCancel := b.cancel
ctx, cancel := context.WithCancel(context.Background())
b.cancel = func() {
oldCancel()
cancel()
}
go b.listenSelectorChange(ctx, b.platformInterface.SelectorCallback)
}
go b.listenSelectorChange(ctx, b.selectorCallback)
}

return nil
Expand All @@ -163,9 +174,8 @@ func (b *BoxInstance) CloseTimeout(timeout time.Duration) (err error) {
return nil
}

if b.protectCloser != nil {
_ = b.protectCloser.Close()
}
_ = common.Close(b.services)

if b.clashModeHook != nil {
select {
case <-b.clashModeHook:
Expand All @@ -176,10 +186,7 @@ func (b *BoxInstance) CloseTimeout(timeout time.Duration) (err error) {
}
}

// close box
done := make(chan struct{})
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
start := time.Now()
go func(done chan<- struct{}) {
defer catchPanic("box.Close", func(panicErr error) { err = panicErr })
Expand All @@ -188,9 +195,12 @@ func (b *BoxInstance) CloseTimeout(timeout time.Duration) (err error) {
close(done)
}(done)
select {
case <-ctx.Done():
case <-time.After(timeout):
return E.New("sing-box did not close in time")
case <-done:
if b.forTest {
return nil
}
log.Info("sing-box closed in ", F.Seconds(time.Since(start).Seconds()), " s.")
return nil
}
Expand All @@ -200,11 +210,6 @@ func (b *BoxInstance) NeedWIFIState() bool {
return b.Box.Router().NeedWIFIState()
}

// SetAsMain starts protect server listening.
func (b *BoxInstance) SetAsMain() {
b.protectCloser = serveProtect(b.protectFun)
}

func (b *BoxInstance) QueryStats(tag, direct string) int64 {
statsGetter := b.Router().V2RayServer().(v2rayapilite.StatsGetter)
if statsGetter == nil {
Expand All @@ -219,7 +224,3 @@ func (b *BoxInstance) SelectOutbound(tag string) (ok bool) {
}
return false
}

func serveProtect(protectFunc protect.Protect) io.Closer {
return protect.ServerProtect(ProtectPath, protectFunc)
}
43 changes: 0 additions & 43 deletions libcore/protect/client.go

This file was deleted.

61 changes: 46 additions & 15 deletions libcore/protect/protect_test.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,48 @@
//go:build unix

package protect

import (
"io"
"context"
"os"
"syscall"
"testing"
"time"

"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions"
)

func TestProtect(t *testing.T) {
const testProtectPath = "protect_test"
closer := ServerProtect(testProtectPath, func(fd int) error {
const (
testProtectPath = "protect_test"
timeout = 5 * time.Second
)
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
service, err := New(ctx, log.StdLogger(), testProtectPath, func(fd int) error {
if fd < 0 {
return E.New("invalid fd: ", fd)
}
return nil
})
if closer == nil {
t.Errorf("ServerProtect failed")
if err != nil {
t.Errorf("create protect service: %v", err)
return
}
defer func(t *testing.T, closer io.Closer) {
if err := closer.Close(); err != nil {
t.Errorf("failed to close: %v", err)
}
}(t, closer)
err = service.Start()
if err != nil {
t.Errorf("start protect server: %v", err)
return
}
defer service.Close()

type clientArg struct {
fd int
path string
}
tests := []struct {
tt := []struct {
name string
arg clientArg
wantErr bool
Expand Down Expand Up @@ -59,11 +72,29 @@ func TestProtect(t *testing.T) {
wantErr: true,
},
}
for _, tt := range tests {
err := ClientProtect(tt.arg.fd, tt.arg.path)
if (err != nil) != tt.wantErr {
t.Errorf("protect failed for [%s]", tt.name)
for _, test := range tt {
do := control.ProtectPath(test.arg.path)
err := do(netUnix, "", fdProvider(test.arg.fd))
if (err != nil) != test.wantErr {
t.Errorf("protect failed for [%s]", test.name)
return
}
}
}

var _ syscall.RawConn = fdProvider(0)

type fdProvider int

func (f fdProvider) Control(ctl func(fd uintptr)) error {
ctl(uintptr(f))
return nil
}

func (f fdProvider) Read(_ func(fd uintptr) (done bool)) error {
return os.ErrInvalid
}

func (f fdProvider) Write(_ func(fd uintptr) (done bool)) error {
return os.ErrInvalid
}
Loading

3 comments on commit 3aca3f4

@re7gog
Copy link
Contributor

@re7gog re7gog commented on 3aca3f4 Oct 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You refactored something this way, that proxy only mode is broken now. Maybe I will fix this later

@re7gog
Copy link
Contributor

@re7gog re7gog commented on 3aca3f4 Oct 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, can you fix this by yourself, looks to difficult for me❤️

@xchacha20-poly1305
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, can you fix this by yourself, looks to difficult for me❤️

a5584a0

Please sign in to comment.