mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-25 18:11:28 +00:00
Fix platform wrapper
This commit is contained in:
parent
60094884cd
commit
140ed9a4cb
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -9,3 +9,4 @@
|
||||||
/build/
|
/build/
|
||||||
/*.jar
|
/*.jar
|
||||||
/*.aar
|
/*.aar
|
||||||
|
/*.xcframework/
|
||||||
|
|
2
box.go
2
box.go
|
@ -78,7 +78,6 @@ func New(ctx context.Context, options option.Options) (*Box, error) {
|
||||||
}
|
}
|
||||||
logWriter = logFile
|
logWriter = logFile
|
||||||
}
|
}
|
||||||
}
|
|
||||||
logFormatter := log.Formatter{
|
logFormatter := log.Formatter{
|
||||||
BaseTime: createdAt,
|
BaseTime: createdAt,
|
||||||
DisableColors: logOptions.DisableColor || logFile != nil,
|
DisableColors: logOptions.DisableColor || logFile != nil,
|
||||||
|
@ -101,6 +100,7 @@ func New(ctx context.Context, options option.Options) (*Box, error) {
|
||||||
} else {
|
} else {
|
||||||
logFactory.SetLevel(log.LevelTrace)
|
logFactory.SetLevel(log.LevelTrace)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
router, err := route.NewRouter(
|
router, err := route.NewRouter(
|
||||||
ctx,
|
ctx,
|
||||||
|
|
|
@ -12,16 +12,32 @@ import (
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/rw"
|
||||||
)
|
)
|
||||||
|
|
||||||
var debugEnabled bool
|
var (
|
||||||
|
debugEnabled bool
|
||||||
|
target string
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.BoolVar(&debugEnabled, "debug", false, "enable debug")
|
flag.BoolVar(&debugEnabled, "debug", false, "enable debug")
|
||||||
|
flag.StringVar(&target, "target", "android", "target platform")
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
build_shared.FindSDK()
|
flag.Parse()
|
||||||
|
|
||||||
build_shared.FindMobile()
|
build_shared.FindMobile()
|
||||||
|
|
||||||
|
switch target {
|
||||||
|
case "android":
|
||||||
|
buildAndroid()
|
||||||
|
case "ios":
|
||||||
|
buildiOS()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildAndroid() {
|
||||||
|
build_shared.FindSDK()
|
||||||
|
|
||||||
args := []string{
|
args := []string{
|
||||||
"bind",
|
"bind",
|
||||||
"-v",
|
"-v",
|
||||||
|
@ -32,10 +48,10 @@ func main() {
|
||||||
if !debugEnabled {
|
if !debugEnabled {
|
||||||
args = append(args,
|
args = append(args,
|
||||||
"-trimpath", "-ldflags=-s -w -buildid=",
|
"-trimpath", "-ldflags=-s -w -buildid=",
|
||||||
"-tags", "with_gvisor,with_quic,with_wireguard,with_utls,with_clash_api,debug",
|
"-tags", "with_gvisor,with_quic,with_wireguard,with_utls,with_clash_api",
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
args = append(args, "-tags", "with_gvisor,with_quic,with_wireguard,with_utls,with_clash_api")
|
args = append(args, "-tags", "with_gvisor,with_quic,with_wireguard,with_utls,with_clash_api,debug")
|
||||||
}
|
}
|
||||||
|
|
||||||
args = append(args, "./experimental/libbox")
|
args = append(args, "./experimental/libbox")
|
||||||
|
@ -59,3 +75,38 @@ func main() {
|
||||||
log.Info("copied to ", copyPath)
|
log.Info("copied to ", copyPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildiOS() {
|
||||||
|
args := []string{
|
||||||
|
"bind",
|
||||||
|
"-v",
|
||||||
|
"-target", "ios,iossimulator,macos",
|
||||||
|
"-libname=box",
|
||||||
|
}
|
||||||
|
if !debugEnabled {
|
||||||
|
args = append(args,
|
||||||
|
"-trimpath", "-ldflags=-s -w -buildid=",
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
args = append(args, "-tags", "debug")
|
||||||
|
}
|
||||||
|
|
||||||
|
args = append(args, "./experimental/libbox")
|
||||||
|
|
||||||
|
command := exec.Command(build_shared.GoBinPath+"/gomobile", args...)
|
||||||
|
command.Stdout = os.Stdout
|
||||||
|
command.Stderr = os.Stderr
|
||||||
|
err := command.Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
copyPath := filepath.Join("..", "sfi")
|
||||||
|
if rw.FileExists(copyPath) {
|
||||||
|
targetDir := filepath.Join(copyPath, "Libbox.xcframework")
|
||||||
|
targetDir, _ = filepath.Abs(targetDir)
|
||||||
|
os.RemoveAll(targetDir)
|
||||||
|
os.Rename("Libbox.xcframework", targetDir)
|
||||||
|
log.Info("copied to ", targetDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
54
experimental/libbox/log.go
Normal file
54
experimental/libbox/log.go
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
package libbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StandardOutput interface {
|
||||||
|
WriteOutput(message string)
|
||||||
|
WriteErrorOutput(message string)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetOutput(output StandardOutput) {
|
||||||
|
log.SetOutput(logWriter{output})
|
||||||
|
pipeIn, pipeOut, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
os.Stdout = os.NewFile(pipeOut.Fd(), "stdout")
|
||||||
|
go lineLog(pipeIn, output.WriteOutput)
|
||||||
|
|
||||||
|
pipeIn, pipeOut, err = os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
os.Stderr = os.NewFile(pipeOut.Fd(), "srderr")
|
||||||
|
go lineLog(pipeIn, output.WriteErrorOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
type logWriter struct {
|
||||||
|
output StandardOutput
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w logWriter) Write(p []byte) (n int, err error) {
|
||||||
|
w.output.WriteOutput(string(p))
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func lineLog(f *os.File, output func(string)) {
|
||||||
|
const logSize = 1024 // matches android/log.h.
|
||||||
|
r := bufio.NewReaderSize(f, logSize)
|
||||||
|
for {
|
||||||
|
line, _, err := r.ReadLine()
|
||||||
|
str := string(line)
|
||||||
|
if err != nil {
|
||||||
|
str += " " + err.Error()
|
||||||
|
}
|
||||||
|
output(str)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
experimental/libbox/log_client.go
Normal file
59
experimental/libbox/log_client.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
//go:build ios
|
||||||
|
|
||||||
|
package libbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LogClient struct {
|
||||||
|
sockPath string
|
||||||
|
handler LogClientHandler
|
||||||
|
conn net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogClientHandler interface {
|
||||||
|
Connected()
|
||||||
|
Disconnected()
|
||||||
|
WriteLog(message string)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLogClient(sharedDirectory string, handler LogClientHandler) *LogClient {
|
||||||
|
return &LogClient{
|
||||||
|
sockPath: filepath.Join(sharedDirectory, "log.sock"),
|
||||||
|
handler: handler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LogClient) Connect() error {
|
||||||
|
conn, err := net.DialUnix("unix", nil, &net.UnixAddr{
|
||||||
|
Name: c.sockPath,
|
||||||
|
Net: "unix",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.conn = conn
|
||||||
|
go c.loopConnection(&messageConn{conn})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LogClient) Disconnect() error {
|
||||||
|
return common.Close(c.conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LogClient) loopConnection(conn *messageConn) {
|
||||||
|
c.handler.Connected()
|
||||||
|
defer c.handler.Disconnected()
|
||||||
|
for {
|
||||||
|
message, err := conn.Read()
|
||||||
|
if err != nil {
|
||||||
|
c.handler.WriteLog("(log client error) " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.handler.WriteLog(string(message))
|
||||||
|
}
|
||||||
|
}
|
139
experimental/libbox/log_server.go
Normal file
139
experimental/libbox/log_server.go
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
//go:build ios
|
||||||
|
|
||||||
|
package libbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/log"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/observable"
|
||||||
|
"github.com/sagernet/sing/common/x/list"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LogServer struct {
|
||||||
|
sockPath string
|
||||||
|
listener net.Listener
|
||||||
|
|
||||||
|
access sync.Mutex
|
||||||
|
savedLines *list.List[string]
|
||||||
|
subscriber *observable.Subscriber[string]
|
||||||
|
observer *observable.Observer[string]
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLogServer(sharedDirectory string) *LogServer {
|
||||||
|
server := &LogServer{
|
||||||
|
sockPath: filepath.Join(sharedDirectory, "log.sock"),
|
||||||
|
savedLines: new(list.List[string]),
|
||||||
|
subscriber: observable.NewSubscriber[string](128),
|
||||||
|
}
|
||||||
|
server.observer = observable.NewObserver[string](server.subscriber, 64)
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LogServer) Start() error {
|
||||||
|
os.Remove(s.sockPath)
|
||||||
|
listener, err := net.ListenUnix("unix", &net.UnixAddr{
|
||||||
|
Name: s.sockPath,
|
||||||
|
Net: "unix",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go s.loopConnection(listener)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LogServer) Close() error {
|
||||||
|
return s.listener.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LogServer) WriteMessage(message string) {
|
||||||
|
s.subscriber.Emit(message)
|
||||||
|
s.access.Lock()
|
||||||
|
s.savedLines.PushBack(message)
|
||||||
|
if s.savedLines.Len() > 100 {
|
||||||
|
s.savedLines.Remove(s.savedLines.Front())
|
||||||
|
}
|
||||||
|
s.access.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LogServer) loopConnection(listener net.Listener) {
|
||||||
|
for {
|
||||||
|
conn, err := listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
hErr := s.handleConnection(&messageConn{conn})
|
||||||
|
if hErr != nil && !E.IsClosed(err) {
|
||||||
|
log.Warn("log-server: process connection: ", hErr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LogServer) handleConnection(conn *messageConn) error {
|
||||||
|
var savedLines []string
|
||||||
|
s.access.Lock()
|
||||||
|
savedLines = make([]string, 0, s.savedLines.Len())
|
||||||
|
for element := s.savedLines.Front(); element != nil; element = element.Next() {
|
||||||
|
savedLines = append(savedLines, element.Value)
|
||||||
|
}
|
||||||
|
s.access.Unlock()
|
||||||
|
subscription, done, err := s.observer.Subscribe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer s.observer.UnSubscribe(subscription)
|
||||||
|
for _, line := range savedLines {
|
||||||
|
err = conn.Write([]byte(line))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case message := <-subscription:
|
||||||
|
err = conn.Write([]byte(message))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case <-done:
|
||||||
|
conn.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type messageConn struct {
|
||||||
|
net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *messageConn) Read() ([]byte, error) {
|
||||||
|
var messageLength uint16
|
||||||
|
err := binary.Read(c.Conn, binary.BigEndian, &messageLength)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
data := make([]byte, messageLength)
|
||||||
|
_, err = io.ReadFull(c.Conn, data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *messageConn) Write(message []byte) error {
|
||||||
|
err := binary.Write(c.Conn, binary.BigEndian, uint16(len(message)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = c.Conn.Write(message)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box"
|
"github.com/sagernet/sing-box"
|
||||||
|
@ -27,6 +28,7 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
platformInterface.WriteLog("Hello " + runtime.GOOS + "/" + runtime.GOARCH)
|
||||||
options.PlatformInterface = &platformInterfaceWrapper{platformInterface, platformInterface.UseProcFS()}
|
options.PlatformInterface = &platformInterfaceWrapper{platformInterface, platformInterface.UseProcFS()}
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
instance, err := box.New(ctx, options)
|
instance, err := box.New(ctx, options)
|
||||||
|
|
|
@ -5,3 +5,7 @@ import C "github.com/sagernet/sing-box/constant"
|
||||||
func SetBasePath(path string) {
|
func SetBasePath(path string) {
|
||||||
C.SetBasePath(path)
|
C.SetBasePath(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Version() string {
|
||||||
|
return C.Version
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
F "github.com/sagernet/sing/common/format"
|
F "github.com/sagernet/sing/common/format"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ func NewFactory(formatter Formatter, writer io.Writer, platformWriter io.Writer)
|
||||||
formatter: formatter,
|
formatter: formatter,
|
||||||
platformFormatter: Formatter{
|
platformFormatter: Formatter{
|
||||||
BaseTime: formatter.BaseTime,
|
BaseTime: formatter.BaseTime,
|
||||||
|
DisableColors: C.IsIos,
|
||||||
},
|
},
|
||||||
writer: writer,
|
writer: writer,
|
||||||
platformWriter: platformWriter,
|
platformWriter: platformWriter,
|
||||||
|
|
Loading…
Reference in a new issue