Skip to content

Commit

Permalink
platform: Add support for tvOS
Browse files Browse the repository at this point in the history
  • Loading branch information
nekohasekai committed Jul 29, 2023
1 parent 1e12f36 commit fa1b5ee
Show file tree
Hide file tree
Showing 8 changed files with 269 additions and 31 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ lib:

lib_install:
go get -v -d
go install -v github.com/sagernet/gomobile/cmd/[email protected]20230701084532-493ee2e45182
go install -v github.com/sagernet/gomobile/cmd/[email protected]20230701084532-493ee2e45182
go install -v github.com/sagernet/gomobile/cmd/[email protected]20230728014906-3de089147f59
go install -v github.com/sagernet/gomobile/cmd/[email protected]20230728014906-3de089147f59

clean:
rm -rf bin dist sing-box
Expand Down
2 changes: 1 addition & 1 deletion cmd/internal/build_libbox/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func buildiOS() {
args := []string{
"bind",
"-v",
"-target", "ios,iossimulator,macos",
"-target", "ios,iossimulator,tvos,tvossimulator,macos",
"-libname=box",
}
if !debugEnabled {
Expand Down
30 changes: 15 additions & 15 deletions experimental/libbox/command_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ import (
)

type CommandClient struct {
sharedDirectory string
handler CommandClientHandler
conn net.Conn
options CommandClientOptions
handler CommandClientHandler
conn net.Conn
options CommandClientOptions
}

type CommandClientOptions struct {
Expand All @@ -29,25 +28,26 @@ type CommandClientHandler interface {
WriteGroups(message OutboundGroupIterator)
}

func NewStandaloneCommandClient(sharedDirectory string) *CommandClient {
return &CommandClient{
sharedDirectory: sharedDirectory,
}
func NewStandaloneCommandClient() *CommandClient {
return new(CommandClient)
}

func NewCommandClient(sharedDirectory string, handler CommandClientHandler, options *CommandClientOptions) *CommandClient {
return &CommandClient{
sharedDirectory: sharedDirectory,
handler: handler,
options: common.PtrValueOrDefault(options),
handler: handler,
options: common.PtrValueOrDefault(options),
}
}

func (c *CommandClient) directConnect() (net.Conn, error) {
return net.DialUnix("unix", nil, &net.UnixAddr{
Name: filepath.Join(c.sharedDirectory, "command.sock"),
Net: "unix",
})
if !sTVOS {
return net.DialUnix("unix", nil, &net.UnixAddr{
Name: filepath.Join(sBasePath, "command.sock"),
Net: "unix",
})
} else {
return net.Dial("tcp", "127.0.0.1:8964")
}
}

func (c *CommandClient) Connect() error {
Expand Down
35 changes: 26 additions & 9 deletions experimental/libbox/command_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
)

type CommandServer struct {
sockPath string
listener net.Listener
handler CommandServerHandler

Expand All @@ -37,9 +36,8 @@ type CommandServerHandler interface {
ServiceReload() error
}

func NewCommandServer(sharedDirectory string, handler CommandServerHandler, maxLines int32) *CommandServer {
func NewCommandServer(handler CommandServerHandler, maxLines int32) *CommandServer {
server := &CommandServer{
sockPath: filepath.Join(sharedDirectory, "command.sock"),
handler: handler,
savedLines: new(list.List[string]),
maxLines: int(maxLines),
Expand Down Expand Up @@ -70,27 +68,46 @@ func (s *CommandServer) notifyURLTestUpdate() {
}

func (s *CommandServer) Start() error {
os.Remove(s.sockPath)
if !sTVOS {
return s.listenUNIX()
} else {
return s.listenTCP()
}
}

func (s *CommandServer) listenUNIX() error {
sockPath := filepath.Join(sBasePath, "command.sock")
os.Remove(sockPath)
listener, err := net.ListenUnix("unix", &net.UnixAddr{
Name: s.sockPath,
Name: sockPath,
Net: "unix",
})
if err != nil {
return err
return E.Cause(err, "listen")
}
if sUserID > 0 {
err = os.Chown(s.sockPath, sUserID, sGroupID)
err = os.Chown(sockPath, sUserID, sGroupID)
if err != nil {
listener.Close()
os.Remove(s.sockPath)
return err
os.Remove(sockPath)
return E.Cause(err, "chown")
}
}
s.listener = listener
go s.loopConnection(listener)
return nil
}

func (s *CommandServer) listenTCP() error {
listener, err := net.Listen("tcp", "127.0.0.1:8964")
if err != nil {
return E.Cause(err, "listen")
}
s.listener = listener
go s.loopConnection(listener)
return nil
}

func (s *CommandServer) Close() error {
return common.Close(
s.listener,
Expand Down
219 changes: 219 additions & 0 deletions experimental/libbox/profile_import.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
package libbox

import (
"bytes"
"encoding/binary"

E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/rw"
)

func EncodeChunkedMessage(data []byte) []byte {
var buffer bytes.Buffer
binary.Write(&buffer, binary.BigEndian, uint16(len(data)))
buffer.Write(data)
return buffer.Bytes()
}

func DecodeLengthChunk(data []byte) int32 {
return int32(binary.BigEndian.Uint16(data))
}

const (
MessageTypeError = iota
MessageTypeProfileList
MessageTypeProfileContentRequest
MessageTypeProfileContent
)

type ErrorMessage struct {
Message string
}

func (e *ErrorMessage) Encode() []byte {
var buffer bytes.Buffer
buffer.WriteByte(MessageTypeError)
rw.WriteVString(&buffer, e.Message)
return buffer.Bytes()
}

func DecodeErrorMessage(data []byte) (*ErrorMessage, error) {
reader := bytes.NewReader(data)
messageType, err := rw.ReadByte(reader)
if err != nil {
return nil, err
}
if messageType != MessageTypeError {
return nil, E.New("invalid message")
}
var message ErrorMessage
message.Message, err = rw.ReadVString(reader)
if err != nil {
return nil, err
}
return &message, nil
}

const (
ProfileTypeLocal int32 = iota
ProfileTypeiCloud
ProfileTypeRemote
)

type ProfilePreview struct {
ProfileID int64
Name string
Type int32
}

type ProfilePreviewIterator interface {
Next() *ProfilePreview
HasNext() bool
}

type ProfileEncoder struct {
profiles []ProfilePreview
}

func (e *ProfileEncoder) Append(profile *ProfilePreview) {
e.profiles = append(e.profiles, *profile)
}

func (e *ProfileEncoder) Encode() []byte {
var buffer bytes.Buffer
buffer.WriteByte(MessageTypeProfileList)
binary.Write(&buffer, binary.BigEndian, uint16(len(e.profiles)))
for _, preview := range e.profiles {
binary.Write(&buffer, binary.BigEndian, preview.ProfileID)
rw.WriteVString(&buffer, preview.Name)
binary.Write(&buffer, binary.BigEndian, preview.Type)
}
return buffer.Bytes()
}

type ProfileDecoder struct {
profiles []*ProfilePreview
}

func (d *ProfileDecoder) Decode(data []byte) error {
reader := bytes.NewReader(data)
messageType, err := reader.ReadByte()
if err != nil {
return err
}
if messageType != MessageTypeProfileList {
return E.New("invalid message")
}
var profileCount uint16
err = binary.Read(reader, binary.BigEndian, &profileCount)
if err != nil {
return err
}
for i := 0; i < int(profileCount); i++ {
var profile ProfilePreview
err = binary.Read(reader, binary.BigEndian, &profile.ProfileID)
if err != nil {
return err
}
profile.Name, err = rw.ReadVString(reader)
if err != nil {
return err
}
err = binary.Read(reader, binary.BigEndian, &profile.Type)
if err != nil {
return err
}
d.profiles = append(d.profiles, &profile)
}
return nil
}

func (d *ProfileDecoder) Iterator() ProfilePreviewIterator {
return newIterator(d.profiles)
}

type ProfileContentRequest struct {
ProfileID int64
}

func (r *ProfileContentRequest) Encode() []byte {
var buffer bytes.Buffer
buffer.WriteByte(MessageTypeProfileContentRequest)
binary.Write(&buffer, binary.BigEndian, r.ProfileID)
return buffer.Bytes()
}

func DecodeProfileContentRequest(data []byte) (*ProfileContentRequest, error) {
reader := bytes.NewReader(data)
messageType, err := rw.ReadByte(reader)
if err != nil {
return nil, err
}
if messageType != MessageTypeProfileContentRequest {
return nil, E.New("invalid message")
}
var request ProfileContentRequest
err = binary.Read(reader, binary.BigEndian, &request.ProfileID)
if err != nil {
return nil, err
}
return &request, nil
}

type ProfileContent struct {
Name string
Type int32
Config string
RemotePath string
AutoUpdate bool
LastUpdated int64
}

func (c *ProfileContent) Encode() []byte {
var buffer bytes.Buffer
buffer.WriteByte(MessageTypeProfileContent)
rw.WriteVString(&buffer, c.Name)
binary.Write(&buffer, binary.BigEndian, c.Type)
rw.WriteVString(&buffer, c.Config)
rw.WriteVString(&buffer, c.RemotePath)
binary.Write(&buffer, binary.BigEndian, c.AutoUpdate)
binary.Write(&buffer, binary.BigEndian, c.LastUpdated)
return buffer.Bytes()
}

func DecodeProfileContent(data []byte) (*ProfileContent, error) {
reader := bytes.NewReader(data)
messageType, err := rw.ReadByte(reader)
if err != nil {
return nil, err
}
if messageType != MessageTypeProfileContent {
return nil, E.New("invalid message")
}
var content ProfileContent
content.Name, err = rw.ReadVString(reader)
if err != nil {
return nil, err
}
err = binary.Read(reader, binary.BigEndian, &content.Type)
if err != nil {
return nil, err
}
content.Config, err = rw.ReadVString(reader)
if err != nil {
return nil, err
}
content.RemotePath, err = rw.ReadVString(reader)
if err != nil {
return nil, err
}
err = binary.Read(reader, binary.BigEndian, &content.AutoUpdate)
if err != nil {
return nil, err
}
err = binary.Read(reader, binary.BigEndian, &content.LastUpdated)
if err != nil {
return nil, err
}
return &content, nil
}
4 changes: 3 additions & 1 deletion experimental/libbox/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ var (
sTempPath string
sUserID int
sGroupID int
sTVOS bool
)

func Setup(basePath string, tempPath string) {
func Setup(basePath string, tempPath string, isTVOS bool) {
sBasePath = basePath
sTempPath = tempPath
sUserID = os.Getuid()
sGroupID = os.Getgid()
sTVOS = isTVOS
}

func SetupWithUsername(basePath string, tempPath string, username string) error {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ require (
github.com/oschwald/maxminddb-golang v1.11.0
github.com/pires/go-proxyproto v0.7.0
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0
github.com/sagernet/gomobile v0.0.0-20230701084532-493ee2e45182
github.com/sagernet/gomobile v0.0.0-20230728014906-3de089147f59
github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2
github.com/sagernet/quic-go v0.0.0-20230615020047-10f05c797c02
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
Expand Down
Loading

0 comments on commit fa1b5ee

Please sign in to comment.