Add USB/IP service
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
//go:build with_usbip && (linux || (darwin && cgo) || windows)
|
||||
|
||||
package usbip
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
boxService "github.com/sagernet/sing-box/adapter/service"
|
||||
"github.com/sagernet/sing-box/common/dialer"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-usbip"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
)
|
||||
|
||||
type ClientService struct {
|
||||
boxService.Adapter
|
||||
ctx context.Context
|
||||
logger log.ContextLogger
|
||||
inner *usbip.ClientService
|
||||
}
|
||||
|
||||
func NewClientService(ctx context.Context, logger log.ContextLogger, tag string, options option.USBIPClientServiceOptions) (adapter.Service, error) {
|
||||
serviceDialer, err := dialer.NewWithOptions(dialer.Options{
|
||||
Context: ctx,
|
||||
Options: option.DialerOptions{
|
||||
Detour: options.Detour,
|
||||
},
|
||||
RemoteIsDomain: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "create dialer")
|
||||
}
|
||||
inner, err := usbip.NewClientService(ctx, usbip.ClientOptions{
|
||||
Logger: logger,
|
||||
Dialer: serviceDialer,
|
||||
ServerAddress: M.ParseSocksaddr(options.Server),
|
||||
Devices: toDeviceMatches(options.Devices),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ClientService{
|
||||
Adapter: boxService.NewAdapter(C.TypeUSBIPClient, tag),
|
||||
ctx: ctx,
|
||||
logger: logger,
|
||||
inner: inner,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *ClientService) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
return s.inner.Start()
|
||||
}
|
||||
|
||||
func (s *ClientService) Close() error {
|
||||
return s.inner.Close()
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
//go:build with_usbip && (linux || (darwin && cgo) || windows)
|
||||
|
||||
package usbip
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
boxService "github.com/sagernet/sing-box/adapter/service"
|
||||
"github.com/sagernet/sing-box/common/listener"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-usbip"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
type ServerService struct {
|
||||
boxService.Adapter
|
||||
ctx context.Context
|
||||
logger log.ContextLogger
|
||||
inner *usbip.ServerService
|
||||
}
|
||||
|
||||
type dynamicServerService struct {
|
||||
ServerService
|
||||
host *usbip.DynamicHost
|
||||
}
|
||||
|
||||
var _ adapter.USBIPDynamicServer = (*dynamicServerService)(nil)
|
||||
|
||||
func NewServerService(ctx context.Context, logger log.ContextLogger, tag string, options option.USBIPServerServiceOptions) (adapter.Service, error) {
|
||||
listenOptions := options.ListenOptions
|
||||
if listenOptions.ListenPort == 0 {
|
||||
listenOptions.ListenPort = usbip.DefaultPort
|
||||
}
|
||||
boxListener := listener.New(listener.Options{
|
||||
Context: ctx,
|
||||
Logger: logger,
|
||||
Network: []string{N.NetworkTCP},
|
||||
Listen: listenOptions,
|
||||
})
|
||||
serverOptions := usbip.ServerOptions{
|
||||
Logger: logger,
|
||||
Listen: func(context.Context) (net.Listener, error) {
|
||||
return boxListener.ListenTCP()
|
||||
},
|
||||
}
|
||||
base := ServerService{
|
||||
Adapter: boxService.NewAdapter(C.TypeUSBIPServer, tag),
|
||||
ctx: ctx,
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
providerType := options.Provider
|
||||
if providerType == "" {
|
||||
providerType = option.USBIPProviderDefault
|
||||
}
|
||||
switch providerType {
|
||||
case option.USBIPProviderDefault:
|
||||
defaultOptions, isDefault := options.Options.(*option.USBIPDefaultProviderOptions)
|
||||
if isDefault {
|
||||
serverOptions.Devices = toDeviceMatches(defaultOptions.Devices)
|
||||
}
|
||||
inner, err := usbip.NewServerService(ctx, serverOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base.inner = inner
|
||||
return &base, nil
|
||||
case option.USBIPProviderDynamic:
|
||||
host := usbip.NewDynamicHost(logger)
|
||||
inner, err := usbip.NewDynamicServerService(ctx, serverOptions, host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base.inner = inner
|
||||
return &dynamicServerService{ServerService: base, host: host}, nil
|
||||
default:
|
||||
return nil, E.New("unknown usbip provider type: ", providerType)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ServerService) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
return s.inner.Start()
|
||||
}
|
||||
|
||||
func (s *ServerService) Close() error {
|
||||
return s.inner.Close()
|
||||
}
|
||||
|
||||
func (s *dynamicServerService) AddDevice(info usbip.DynamicDeviceInfo, transport usbip.DeviceTransport) (string, error) {
|
||||
return s.host.AddDevice(info, transport)
|
||||
}
|
||||
|
||||
func (s *dynamicServerService) RemoveDevice(busID string) {
|
||||
s.host.RemoveDevice(busID)
|
||||
}
|
||||
|
||||
func (s *dynamicServerService) SubscribeDevices(ctx context.Context, listener func([]usbip.ControlDeviceInfo)) {
|
||||
s.inner.SubscribeDevices(ctx, listener)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
//go:build with_usbip && (linux || (darwin && cgo) || windows)
|
||||
|
||||
package usbip
|
||||
|
||||
import (
|
||||
boxService "github.com/sagernet/sing-box/adapter/service"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-usbip"
|
||||
)
|
||||
|
||||
func RegisterService(registry *boxService.Registry) {
|
||||
boxService.Register[option.USBIPServerServiceOptions](registry, C.TypeUSBIPServer, NewServerService)
|
||||
boxService.Register[option.USBIPClientServiceOptions](registry, C.TypeUSBIPClient, NewClientService)
|
||||
}
|
||||
|
||||
func toDeviceMatches(matches []option.USBIPDeviceMatch) []usbip.DeviceMatch {
|
||||
if len(matches) == 0 {
|
||||
return nil
|
||||
}
|
||||
deviceMatches := make([]usbip.DeviceMatch, 0, len(matches))
|
||||
for _, match := range matches {
|
||||
deviceMatches = append(deviceMatches, usbip.DeviceMatch{
|
||||
BusID: match.BusID,
|
||||
VendorID: match.VendorID,
|
||||
ProductID: match.ProductID,
|
||||
Serial: match.Serial,
|
||||
})
|
||||
}
|
||||
return deviceMatches
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
//go:build !with_usbip || !(linux || (darwin && cgo) || windows)
|
||||
|
||||
package usbip
|
||||
Reference in New Issue
Block a user