diff --git a/adapter/usbip.go b/adapter/usbip.go new file mode 100644 index 000000000..e334476d5 --- /dev/null +++ b/adapter/usbip.go @@ -0,0 +1,15 @@ +//go:build with_usbip && (linux || (darwin && cgo) || windows) + +package adapter + +import ( + "context" + + "github.com/sagernet/sing-usbip" +) + +type USBIPDynamicServer interface { + AddDevice(info usbip.DynamicDeviceInfo, transport usbip.DeviceTransport) (string, error) + RemoveDevice(busID string) + SubscribeDevices(ctx context.Context, listener func([]usbip.ControlDeviceInfo)) +} diff --git a/adapter/usbip_stub.go b/adapter/usbip_stub.go new file mode 100644 index 000000000..14db605a7 --- /dev/null +++ b/adapter/usbip_stub.go @@ -0,0 +1,7 @@ +//go:build !with_usbip || !(linux || (darwin && cgo) || windows) + +package adapter + +type USBIPDynamicServer interface { + usbipNotIncluded() +} diff --git a/constant/proxy.go b/constant/proxy.go index 3aa8f3d78..ea6517124 100644 --- a/constant/proxy.go +++ b/constant/proxy.go @@ -33,6 +33,8 @@ const ( TypeCCM = "ccm" TypeOCM = "ocm" TypeOOMKiller = "oom-killer" + TypeUSBIPServer = "usbip-server" + TypeUSBIPClient = "usbip-client" TypeHysteriaRealm = "hysteria-realm" TypeACME = "acme" TypeCloudflareOriginCA = "cloudflare-origin-ca" diff --git a/daemon/managed_service.go b/daemon/managed_service.go index 922a1d15c..eb14d7bf1 100644 --- a/daemon/managed_service.go +++ b/daemon/managed_service.go @@ -5,6 +5,9 @@ import ( "time" "unsafe" + "github.com/sagernet/sing-box/service/oomkiller" + "github.com/sagernet/sing/common/memory" + "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/emptypb" @@ -13,19 +16,22 @@ import ( var _ ManagedServiceServer = (*ManagedService)(nil) type ManagedService struct { - handler ManagedHandler - debug bool + handler ManagedHandler + debug bool + oomReporter oomkiller.OOMReporter } type ManagedServiceOptions struct { - Handler ManagedHandler - Debug bool + Handler ManagedHandler + Debug bool + OOMReporter oomkiller.OOMReporter } func NewManagedService(options ManagedServiceOptions) *ManagedService { return &ManagedService{ - handler: options.Handler, - debug: options.Debug, + handler: options.Handler, + debug: options.Debug, + oomReporter: options.OOMReporter, } } @@ -80,5 +86,12 @@ func (s *ManagedService) TriggerDebugCrash(ctx context.Context, request *DebugCr return &emptypb.Empty{}, nil } +func (s *ManagedService) TriggerOOMReport(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) { + if s.oomReporter == nil { + return nil, status.Error(codes.Unavailable, "OOM reporter not available") + } + return &emptypb.Empty{}, s.oomReporter.WriteReport(memory.Total()) +} + func (s *ManagedService) mustEmbedUnimplementedManagedServiceServer() { } diff --git a/daemon/managed_service.pb.go b/daemon/managed_service.pb.go index 2ca6b614a..56af7eb30 100644 --- a/daemon/managed_service.pb.go +++ b/daemon/managed_service.pb.go @@ -218,13 +218,14 @@ const file_daemon_managed_service_proto_rawDesc = "" + "\x04Type\x12\x06\n" + "\x02GO\x10\x00\x12\n" + "\n" + - "\x06NATIVE\x10\x012\x80\x03\n" + + "\x06NATIVE\x10\x012\xc6\x03\n" + "\x0eManagedService\x12=\n" + "\vStopService\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\x12?\n" + "\rReloadService\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\x12K\n" + "\x14GetSystemProxyStatus\x12\x16.google.protobuf.Empty\x1a\x19.daemon.SystemProxyStatus\"\x00\x12W\n" + "\x15SetSystemProxyEnabled\x12$.daemon.SetSystemProxyEnabledRequest\x1a\x16.google.protobuf.Empty\"\x00\x12H\n" + - "\x11TriggerDebugCrash\x12\x19.daemon.DebugCrashRequest\x1a\x16.google.protobuf.Empty\"\x00B%Z#github.com/sagernet/sing-box/daemonb\x06proto3" + "\x11TriggerDebugCrash\x12\x19.daemon.DebugCrashRequest\x1a\x16.google.protobuf.Empty\"\x00\x12D\n" + + "\x10TriggerOOMReport\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\"\x00B%Z#github.com/sagernet/sing-box/daemonb\x06proto3" var ( file_daemon_managed_service_proto_rawDescOnce sync.Once @@ -257,13 +258,15 @@ var file_daemon_managed_service_proto_depIdxs = []int32{ 4, // 3: daemon.ManagedService.GetSystemProxyStatus:input_type -> google.protobuf.Empty 2, // 4: daemon.ManagedService.SetSystemProxyEnabled:input_type -> daemon.SetSystemProxyEnabledRequest 3, // 5: daemon.ManagedService.TriggerDebugCrash:input_type -> daemon.DebugCrashRequest - 4, // 6: daemon.ManagedService.StopService:output_type -> google.protobuf.Empty - 4, // 7: daemon.ManagedService.ReloadService:output_type -> google.protobuf.Empty - 1, // 8: daemon.ManagedService.GetSystemProxyStatus:output_type -> daemon.SystemProxyStatus - 4, // 9: daemon.ManagedService.SetSystemProxyEnabled:output_type -> google.protobuf.Empty - 4, // 10: daemon.ManagedService.TriggerDebugCrash:output_type -> google.protobuf.Empty - 6, // [6:11] is the sub-list for method output_type - 1, // [1:6] is the sub-list for method input_type + 4, // 6: daemon.ManagedService.TriggerOOMReport:input_type -> google.protobuf.Empty + 4, // 7: daemon.ManagedService.StopService:output_type -> google.protobuf.Empty + 4, // 8: daemon.ManagedService.ReloadService:output_type -> google.protobuf.Empty + 1, // 9: daemon.ManagedService.GetSystemProxyStatus:output_type -> daemon.SystemProxyStatus + 4, // 10: daemon.ManagedService.SetSystemProxyEnabled:output_type -> google.protobuf.Empty + 4, // 11: daemon.ManagedService.TriggerDebugCrash:output_type -> google.protobuf.Empty + 4, // 12: daemon.ManagedService.TriggerOOMReport:output_type -> google.protobuf.Empty + 7, // [7:13] is the sub-list for method output_type + 1, // [1:7] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name 1, // [1:1] is the sub-list for extension extendee 0, // [0:1] is the sub-list for field type_name diff --git a/daemon/managed_service.proto b/daemon/managed_service.proto index 9626fd847..32777948b 100644 --- a/daemon/managed_service.proto +++ b/daemon/managed_service.proto @@ -12,6 +12,7 @@ service ManagedService { rpc GetSystemProxyStatus(google.protobuf.Empty) returns(SystemProxyStatus) {} rpc SetSystemProxyEnabled(SetSystemProxyEnabledRequest) returns(google.protobuf.Empty) {} rpc TriggerDebugCrash(DebugCrashRequest) returns(google.protobuf.Empty) {} + rpc TriggerOOMReport(google.protobuf.Empty) returns(google.protobuf.Empty) {} } message SystemProxyStatus { diff --git a/daemon/managed_service_grpc.pb.go b/daemon/managed_service_grpc.pb.go index 668627f6f..75832a788 100644 --- a/daemon/managed_service_grpc.pb.go +++ b/daemon/managed_service_grpc.pb.go @@ -20,6 +20,7 @@ const ( ManagedService_GetSystemProxyStatus_FullMethodName = "/daemon.ManagedService/GetSystemProxyStatus" ManagedService_SetSystemProxyEnabled_FullMethodName = "/daemon.ManagedService/SetSystemProxyEnabled" ManagedService_TriggerDebugCrash_FullMethodName = "/daemon.ManagedService/TriggerDebugCrash" + ManagedService_TriggerOOMReport_FullMethodName = "/daemon.ManagedService/TriggerOOMReport" ) // ManagedServiceClient is the client API for ManagedService service. @@ -31,6 +32,7 @@ type ManagedServiceClient interface { GetSystemProxyStatus(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*SystemProxyStatus, error) SetSystemProxyEnabled(ctx context.Context, in *SetSystemProxyEnabledRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) TriggerDebugCrash(ctx context.Context, in *DebugCrashRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + TriggerOOMReport(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) } type managedServiceClient struct { @@ -91,6 +93,16 @@ func (c *managedServiceClient) TriggerDebugCrash(ctx context.Context, in *DebugC return out, nil } +func (c *managedServiceClient) TriggerOOMReport(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, ManagedService_TriggerOOMReport_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // ManagedServiceServer is the server API for ManagedService service. // All implementations must embed UnimplementedManagedServiceServer // for forward compatibility. @@ -100,6 +112,7 @@ type ManagedServiceServer interface { GetSystemProxyStatus(context.Context, *emptypb.Empty) (*SystemProxyStatus, error) SetSystemProxyEnabled(context.Context, *SetSystemProxyEnabledRequest) (*emptypb.Empty, error) TriggerDebugCrash(context.Context, *DebugCrashRequest) (*emptypb.Empty, error) + TriggerOOMReport(context.Context, *emptypb.Empty) (*emptypb.Empty, error) mustEmbedUnimplementedManagedServiceServer() } @@ -129,6 +142,10 @@ func (UnimplementedManagedServiceServer) SetSystemProxyEnabled(context.Context, func (UnimplementedManagedServiceServer) TriggerDebugCrash(context.Context, *DebugCrashRequest) (*emptypb.Empty, error) { return nil, status.Error(codes.Unimplemented, "method TriggerDebugCrash not implemented") } + +func (UnimplementedManagedServiceServer) TriggerOOMReport(context.Context, *emptypb.Empty) (*emptypb.Empty, error) { + return nil, status.Error(codes.Unimplemented, "method TriggerOOMReport not implemented") +} func (UnimplementedManagedServiceServer) mustEmbedUnimplementedManagedServiceServer() {} func (UnimplementedManagedServiceServer) testEmbeddedByValue() {} @@ -240,6 +257,24 @@ func _ManagedService_TriggerDebugCrash_Handler(srv interface{}, ctx context.Cont return interceptor(ctx, in, info, handler) } +func _ManagedService_TriggerOOMReport_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(emptypb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ManagedServiceServer).TriggerOOMReport(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ManagedService_TriggerOOMReport_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ManagedServiceServer).TriggerOOMReport(ctx, req.(*emptypb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + // ManagedService_ServiceDesc is the grpc.ServiceDesc for ManagedService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -267,6 +302,10 @@ var ManagedService_ServiceDesc = grpc.ServiceDesc{ MethodName: "TriggerDebugCrash", Handler: _ManagedService_TriggerDebugCrash_Handler, }, + { + MethodName: "TriggerOOMReport", + Handler: _ManagedService_TriggerOOMReport_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "daemon/managed_service.proto", diff --git a/daemon/started_service.go b/daemon/started_service.go index db9ff7fb8..d6187dbec 100644 --- a/daemon/started_service.go +++ b/daemon/started_service.go @@ -17,7 +17,6 @@ import ( "github.com/sagernet/sing-box/experimental/deprecated" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/protocol/group" - "github.com/sagernet/sing-box/service/oomkiller" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/batch" "github.com/sagernet/sing/common/memory" @@ -32,7 +31,7 @@ import ( "google.golang.org/protobuf/types/known/emptypb" ) -const APIVersion = 1 +const APIVersion = 2 var _ StartedServiceServer = (*StartedService)(nil) @@ -669,18 +668,6 @@ func (s *StartedService) SetGroupExpand(ctx context.Context, request *SetGroupEx return &emptypb.Empty{}, nil } -func (s *StartedService) TriggerOOMReport(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) { - instance := s.Instance() - if instance == nil { - return nil, status.Error(codes.FailedPrecondition, "service not started") - } - reporter := service.FromContext[oomkiller.OOMReporter](instance.ctx) - if reporter == nil { - return nil, status.Error(codes.Unavailable, "OOM reporter not available") - } - return &emptypb.Empty{}, reporter.WriteReport(memory.Total()) -} - func (s *StartedService) SubscribeConnections(request *SubscribeConnectionsRequest, server grpc.ServerStreamingServer[ConnectionEvents]) error { err := s.waitForStarted(server.Context()) if err != nil { diff --git a/daemon/started_service.pb.go b/daemon/started_service.pb.go index 88ee18225..8b0782a15 100644 --- a/daemon/started_service.pb.go +++ b/daemon/started_service.pb.go @@ -127,6 +127,110 @@ func (ConnectionEventType) EnumDescriptor() ([]byte, []int) { return file_daemon_started_service_proto_rawDescGZIP(), []int{1} } +type USBDeviceState int32 + +const ( + USBDeviceState_USB_DEVICE_STATE_IDLE USBDeviceState = 0 + USBDeviceState_USB_DEVICE_STATE_ATTACHED USBDeviceState = 1 + USBDeviceState_USB_DEVICE_STATE_UNAVAILABLE USBDeviceState = 2 +) + +// Enum value maps for USBDeviceState. +var ( + USBDeviceState_name = map[int32]string{ + 0: "USB_DEVICE_STATE_IDLE", + 1: "USB_DEVICE_STATE_ATTACHED", + 2: "USB_DEVICE_STATE_UNAVAILABLE", + } + USBDeviceState_value = map[string]int32{ + "USB_DEVICE_STATE_IDLE": 0, + "USB_DEVICE_STATE_ATTACHED": 1, + "USB_DEVICE_STATE_UNAVAILABLE": 2, + } +) + +func (x USBDeviceState) Enum() *USBDeviceState { + p := new(USBDeviceState) + *p = x + return p +} + +func (x USBDeviceState) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (USBDeviceState) Descriptor() protoreflect.EnumDescriptor { + return file_daemon_started_service_proto_enumTypes[2].Descriptor() +} + +func (USBDeviceState) Type() protoreflect.EnumType { + return &file_daemon_started_service_proto_enumTypes[2] +} + +func (x USBDeviceState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use USBDeviceState.Descriptor instead. +func (USBDeviceState) EnumDescriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{2} +} + +type USBBackend int32 + +const ( + USBBackend_USB_BACKEND_UNSPECIFIED USBBackend = 0 + USBBackend_USB_BACKEND_LINUX_SYSFS USBBackend = 1 + USBBackend_USB_BACKEND_DYNAMIC USBBackend = 2 + USBBackend_USB_BACKEND_DARWIN_IOKIT USBBackend = 3 + USBBackend_USB_BACKEND_WINDOWS_VBOXUSB USBBackend = 4 +) + +// Enum value maps for USBBackend. +var ( + USBBackend_name = map[int32]string{ + 0: "USB_BACKEND_UNSPECIFIED", + 1: "USB_BACKEND_LINUX_SYSFS", + 2: "USB_BACKEND_DYNAMIC", + 3: "USB_BACKEND_DARWIN_IOKIT", + 4: "USB_BACKEND_WINDOWS_VBOXUSB", + } + USBBackend_value = map[string]int32{ + "USB_BACKEND_UNSPECIFIED": 0, + "USB_BACKEND_LINUX_SYSFS": 1, + "USB_BACKEND_DYNAMIC": 2, + "USB_BACKEND_DARWIN_IOKIT": 3, + "USB_BACKEND_WINDOWS_VBOXUSB": 4, + } +) + +func (x USBBackend) Enum() *USBBackend { + p := new(USBBackend) + *p = x + return p +} + +func (x USBBackend) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (USBBackend) Descriptor() protoreflect.EnumDescriptor { + return file_daemon_started_service_proto_enumTypes[3].Descriptor() +} + +func (USBBackend) Type() protoreflect.EnumType { + return &file_daemon_started_service_proto_enumTypes[3] +} + +func (x USBBackend) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use USBBackend.Descriptor instead. +func (USBBackend) EnumDescriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{3} +} + type ServiceStatus_Type int32 const ( @@ -166,11 +270,11 @@ func (x ServiceStatus_Type) String() string { } func (ServiceStatus_Type) Descriptor() protoreflect.EnumDescriptor { - return file_daemon_started_service_proto_enumTypes[2].Descriptor() + return file_daemon_started_service_proto_enumTypes[4].Descriptor() } func (ServiceStatus_Type) Type() protoreflect.EnumType { - return &file_daemon_started_service_proto_enumTypes[2] + return &file_daemon_started_service_proto_enumTypes[4] } func (x ServiceStatus_Type) Number() protoreflect.EnumNumber { @@ -3378,6 +3482,1142 @@ func (x *TailscaleSSHError) GetMessage() string { return "" } +type USBProviderMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Message: + // + // *USBProviderMessage_Attach + // *USBProviderMessage_Detach + // *USBProviderMessage_UrbResponse + Message isUSBProviderMessage_Message `protobuf_oneof:"message"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *USBProviderMessage) Reset() { + *x = USBProviderMessage{} + mi := &file_daemon_started_service_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *USBProviderMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*USBProviderMessage) ProtoMessage() {} + +func (x *USBProviderMessage) ProtoReflect() protoreflect.Message { + mi := &file_daemon_started_service_proto_msgTypes[46] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use USBProviderMessage.ProtoReflect.Descriptor instead. +func (*USBProviderMessage) Descriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{46} +} + +func (x *USBProviderMessage) GetMessage() isUSBProviderMessage_Message { + if x != nil { + return x.Message + } + return nil +} + +func (x *USBProviderMessage) GetAttach() *USBDeviceAttach { + if x != nil { + if x, ok := x.Message.(*USBProviderMessage_Attach); ok { + return x.Attach + } + } + return nil +} + +func (x *USBProviderMessage) GetDetach() *USBDeviceDetach { + if x != nil { + if x, ok := x.Message.(*USBProviderMessage_Detach); ok { + return x.Detach + } + } + return nil +} + +func (x *USBProviderMessage) GetUrbResponse() *USBURBResponse { + if x != nil { + if x, ok := x.Message.(*USBProviderMessage_UrbResponse); ok { + return x.UrbResponse + } + } + return nil +} + +type isUSBProviderMessage_Message interface { + isUSBProviderMessage_Message() +} + +type USBProviderMessage_Attach struct { + Attach *USBDeviceAttach `protobuf:"bytes,1,opt,name=attach,proto3,oneof"` +} + +type USBProviderMessage_Detach struct { + Detach *USBDeviceDetach `protobuf:"bytes,2,opt,name=detach,proto3,oneof"` +} + +type USBProviderMessage_UrbResponse struct { + UrbResponse *USBURBResponse `protobuf:"bytes,3,opt,name=urbResponse,proto3,oneof"` +} + +func (*USBProviderMessage_Attach) isUSBProviderMessage_Message() {} + +func (*USBProviderMessage_Detach) isUSBProviderMessage_Message() {} + +func (*USBProviderMessage_UrbResponse) isUSBProviderMessage_Message() {} + +type USBServerMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Message: + // + // *USBServerMessage_Ready + // *USBServerMessage_UrbRequest + // *USBServerMessage_Abort + // *USBServerMessage_Error + Message isUSBServerMessage_Message `protobuf_oneof:"message"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *USBServerMessage) Reset() { + *x = USBServerMessage{} + mi := &file_daemon_started_service_proto_msgTypes[47] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *USBServerMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*USBServerMessage) ProtoMessage() {} + +func (x *USBServerMessage) ProtoReflect() protoreflect.Message { + mi := &file_daemon_started_service_proto_msgTypes[47] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use USBServerMessage.ProtoReflect.Descriptor instead. +func (*USBServerMessage) Descriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{47} +} + +func (x *USBServerMessage) GetMessage() isUSBServerMessage_Message { + if x != nil { + return x.Message + } + return nil +} + +func (x *USBServerMessage) GetReady() *USBDeviceReady { + if x != nil { + if x, ok := x.Message.(*USBServerMessage_Ready); ok { + return x.Ready + } + } + return nil +} + +func (x *USBServerMessage) GetUrbRequest() *USBURBRequest { + if x != nil { + if x, ok := x.Message.(*USBServerMessage_UrbRequest); ok { + return x.UrbRequest + } + } + return nil +} + +func (x *USBServerMessage) GetAbort() *USBEndpointAbort { + if x != nil { + if x, ok := x.Message.(*USBServerMessage_Abort); ok { + return x.Abort + } + } + return nil +} + +func (x *USBServerMessage) GetError() *USBError { + if x != nil { + if x, ok := x.Message.(*USBServerMessage_Error); ok { + return x.Error + } + } + return nil +} + +type isUSBServerMessage_Message interface { + isUSBServerMessage_Message() +} + +type USBServerMessage_Ready struct { + Ready *USBDeviceReady `protobuf:"bytes,1,opt,name=ready,proto3,oneof"` +} + +type USBServerMessage_UrbRequest struct { + UrbRequest *USBURBRequest `protobuf:"bytes,2,opt,name=urbRequest,proto3,oneof"` +} + +type USBServerMessage_Abort struct { + Abort *USBEndpointAbort `protobuf:"bytes,3,opt,name=abort,proto3,oneof"` +} + +type USBServerMessage_Error struct { + Error *USBError `protobuf:"bytes,4,opt,name=error,proto3,oneof"` +} + +func (*USBServerMessage_Ready) isUSBServerMessage_Message() {} + +func (*USBServerMessage_UrbRequest) isUSBServerMessage_Message() {} + +func (*USBServerMessage_Abort) isUSBServerMessage_Message() {} + +func (*USBServerMessage_Error) isUSBServerMessage_Message() {} + +type USBDeviceDescriptor struct { + state protoimpl.MessageState `protogen:"open.v1"` + DeviceId string `protobuf:"bytes,1,opt,name=deviceId,proto3" json:"deviceId,omitempty"` + BusNum uint32 `protobuf:"varint,2,opt,name=busNum,proto3" json:"busNum,omitempty"` + DevNum uint32 `protobuf:"varint,3,opt,name=devNum,proto3" json:"devNum,omitempty"` + Speed uint32 `protobuf:"varint,4,opt,name=speed,proto3" json:"speed,omitempty"` + VendorId uint32 `protobuf:"varint,5,opt,name=vendorId,proto3" json:"vendorId,omitempty"` + ProductId uint32 `protobuf:"varint,6,opt,name=productId,proto3" json:"productId,omitempty"` + BcdDevice uint32 `protobuf:"varint,7,opt,name=bcdDevice,proto3" json:"bcdDevice,omitempty"` + DeviceClass uint32 `protobuf:"varint,8,opt,name=deviceClass,proto3" json:"deviceClass,omitempty"` + DeviceSubClass uint32 `protobuf:"varint,9,opt,name=deviceSubClass,proto3" json:"deviceSubClass,omitempty"` + DeviceProtocol uint32 `protobuf:"varint,10,opt,name=deviceProtocol,proto3" json:"deviceProtocol,omitempty"` + ConfigurationValue uint32 `protobuf:"varint,11,opt,name=configurationValue,proto3" json:"configurationValue,omitempty"` + NumConfigurations uint32 `protobuf:"varint,12,opt,name=numConfigurations,proto3" json:"numConfigurations,omitempty"` + Interfaces []*USBInterface `protobuf:"bytes,13,rep,name=interfaces,proto3" json:"interfaces,omitempty"` + Serial string `protobuf:"bytes,14,opt,name=serial,proto3" json:"serial,omitempty"` + Product string `protobuf:"bytes,15,opt,name=product,proto3" json:"product,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *USBDeviceDescriptor) Reset() { + *x = USBDeviceDescriptor{} + mi := &file_daemon_started_service_proto_msgTypes[48] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *USBDeviceDescriptor) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*USBDeviceDescriptor) ProtoMessage() {} + +func (x *USBDeviceDescriptor) ProtoReflect() protoreflect.Message { + mi := &file_daemon_started_service_proto_msgTypes[48] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use USBDeviceDescriptor.ProtoReflect.Descriptor instead. +func (*USBDeviceDescriptor) Descriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{48} +} + +func (x *USBDeviceDescriptor) GetDeviceId() string { + if x != nil { + return x.DeviceId + } + return "" +} + +func (x *USBDeviceDescriptor) GetBusNum() uint32 { + if x != nil { + return x.BusNum + } + return 0 +} + +func (x *USBDeviceDescriptor) GetDevNum() uint32 { + if x != nil { + return x.DevNum + } + return 0 +} + +func (x *USBDeviceDescriptor) GetSpeed() uint32 { + if x != nil { + return x.Speed + } + return 0 +} + +func (x *USBDeviceDescriptor) GetVendorId() uint32 { + if x != nil { + return x.VendorId + } + return 0 +} + +func (x *USBDeviceDescriptor) GetProductId() uint32 { + if x != nil { + return x.ProductId + } + return 0 +} + +func (x *USBDeviceDescriptor) GetBcdDevice() uint32 { + if x != nil { + return x.BcdDevice + } + return 0 +} + +func (x *USBDeviceDescriptor) GetDeviceClass() uint32 { + if x != nil { + return x.DeviceClass + } + return 0 +} + +func (x *USBDeviceDescriptor) GetDeviceSubClass() uint32 { + if x != nil { + return x.DeviceSubClass + } + return 0 +} + +func (x *USBDeviceDescriptor) GetDeviceProtocol() uint32 { + if x != nil { + return x.DeviceProtocol + } + return 0 +} + +func (x *USBDeviceDescriptor) GetConfigurationValue() uint32 { + if x != nil { + return x.ConfigurationValue + } + return 0 +} + +func (x *USBDeviceDescriptor) GetNumConfigurations() uint32 { + if x != nil { + return x.NumConfigurations + } + return 0 +} + +func (x *USBDeviceDescriptor) GetInterfaces() []*USBInterface { + if x != nil { + return x.Interfaces + } + return nil +} + +func (x *USBDeviceDescriptor) GetSerial() string { + if x != nil { + return x.Serial + } + return "" +} + +func (x *USBDeviceDescriptor) GetProduct() string { + if x != nil { + return x.Product + } + return "" +} + +type USBDeviceAttach struct { + state protoimpl.MessageState `protogen:"open.v1"` + ServerTag string `protobuf:"bytes,1,opt,name=serverTag,proto3" json:"serverTag,omitempty"` + Descriptor_ *USBDeviceDescriptor `protobuf:"bytes,2,opt,name=descriptor,proto3" json:"descriptor,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *USBDeviceAttach) Reset() { + *x = USBDeviceAttach{} + mi := &file_daemon_started_service_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *USBDeviceAttach) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*USBDeviceAttach) ProtoMessage() {} + +func (x *USBDeviceAttach) ProtoReflect() protoreflect.Message { + mi := &file_daemon_started_service_proto_msgTypes[49] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use USBDeviceAttach.ProtoReflect.Descriptor instead. +func (*USBDeviceAttach) Descriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{49} +} + +func (x *USBDeviceAttach) GetServerTag() string { + if x != nil { + return x.ServerTag + } + return "" +} + +func (x *USBDeviceAttach) GetDescriptor_() *USBDeviceDescriptor { + if x != nil { + return x.Descriptor_ + } + return nil +} + +type USBInterface struct { + state protoimpl.MessageState `protogen:"open.v1"` + InterfaceClass uint32 `protobuf:"varint,1,opt,name=interfaceClass,proto3" json:"interfaceClass,omitempty"` + InterfaceSubClass uint32 `protobuf:"varint,2,opt,name=interfaceSubClass,proto3" json:"interfaceSubClass,omitempty"` + InterfaceProtocol uint32 `protobuf:"varint,3,opt,name=interfaceProtocol,proto3" json:"interfaceProtocol,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *USBInterface) Reset() { + *x = USBInterface{} + mi := &file_daemon_started_service_proto_msgTypes[50] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *USBInterface) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*USBInterface) ProtoMessage() {} + +func (x *USBInterface) ProtoReflect() protoreflect.Message { + mi := &file_daemon_started_service_proto_msgTypes[50] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use USBInterface.ProtoReflect.Descriptor instead. +func (*USBInterface) Descriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{50} +} + +func (x *USBInterface) GetInterfaceClass() uint32 { + if x != nil { + return x.InterfaceClass + } + return 0 +} + +func (x *USBInterface) GetInterfaceSubClass() uint32 { + if x != nil { + return x.InterfaceSubClass + } + return 0 +} + +func (x *USBInterface) GetInterfaceProtocol() uint32 { + if x != nil { + return x.InterfaceProtocol + } + return 0 +} + +type USBDeviceDetach struct { + state protoimpl.MessageState `protogen:"open.v1"` + DeviceId string `protobuf:"bytes,1,opt,name=deviceId,proto3" json:"deviceId,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *USBDeviceDetach) Reset() { + *x = USBDeviceDetach{} + mi := &file_daemon_started_service_proto_msgTypes[51] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *USBDeviceDetach) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*USBDeviceDetach) ProtoMessage() {} + +func (x *USBDeviceDetach) ProtoReflect() protoreflect.Message { + mi := &file_daemon_started_service_proto_msgTypes[51] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use USBDeviceDetach.ProtoReflect.Descriptor instead. +func (*USBDeviceDetach) Descriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{51} +} + +func (x *USBDeviceDetach) GetDeviceId() string { + if x != nil { + return x.DeviceId + } + return "" +} + +type USBDeviceReady struct { + state protoimpl.MessageState `protogen:"open.v1"` + DeviceId string `protobuf:"bytes,1,opt,name=deviceId,proto3" json:"deviceId,omitempty"` + BusId string `protobuf:"bytes,2,opt,name=busId,proto3" json:"busId,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *USBDeviceReady) Reset() { + *x = USBDeviceReady{} + mi := &file_daemon_started_service_proto_msgTypes[52] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *USBDeviceReady) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*USBDeviceReady) ProtoMessage() {} + +func (x *USBDeviceReady) ProtoReflect() protoreflect.Message { + mi := &file_daemon_started_service_proto_msgTypes[52] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use USBDeviceReady.ProtoReflect.Descriptor instead. +func (*USBDeviceReady) Descriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{52} +} + +func (x *USBDeviceReady) GetDeviceId() string { + if x != nil { + return x.DeviceId + } + return "" +} + +func (x *USBDeviceReady) GetBusId() string { + if x != nil { + return x.BusId + } + return "" +} + +type USBURBRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + DeviceId string `protobuf:"bytes,1,opt,name=deviceId,proto3" json:"deviceId,omitempty"` + Seq uint64 `protobuf:"varint,2,opt,name=seq,proto3" json:"seq,omitempty"` + Endpoint uint32 `protobuf:"varint,3,opt,name=endpoint,proto3" json:"endpoint,omitempty"` + DirectionIn bool `protobuf:"varint,4,opt,name=directionIn,proto3" json:"directionIn,omitempty"` + TransferFlags uint32 `protobuf:"varint,5,opt,name=transferFlags,proto3" json:"transferFlags,omitempty"` + Setup []byte `protobuf:"bytes,6,opt,name=setup,proto3" json:"setup,omitempty"` + TransferBufferLength uint32 `protobuf:"varint,7,opt,name=transferBufferLength,proto3" json:"transferBufferLength,omitempty"` + OutData []byte `protobuf:"bytes,8,opt,name=outData,proto3" json:"outData,omitempty"` + NumberOfPackets int32 `protobuf:"varint,9,opt,name=numberOfPackets,proto3" json:"numberOfPackets,omitempty"` + StartFrame int32 `protobuf:"varint,10,opt,name=startFrame,proto3" json:"startFrame,omitempty"` + Interval int32 `protobuf:"varint,11,opt,name=interval,proto3" json:"interval,omitempty"` + IsoPackets []*USBIsoPacket `protobuf:"bytes,12,rep,name=isoPackets,proto3" json:"isoPackets,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *USBURBRequest) Reset() { + *x = USBURBRequest{} + mi := &file_daemon_started_service_proto_msgTypes[53] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *USBURBRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*USBURBRequest) ProtoMessage() {} + +func (x *USBURBRequest) ProtoReflect() protoreflect.Message { + mi := &file_daemon_started_service_proto_msgTypes[53] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use USBURBRequest.ProtoReflect.Descriptor instead. +func (*USBURBRequest) Descriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{53} +} + +func (x *USBURBRequest) GetDeviceId() string { + if x != nil { + return x.DeviceId + } + return "" +} + +func (x *USBURBRequest) GetSeq() uint64 { + if x != nil { + return x.Seq + } + return 0 +} + +func (x *USBURBRequest) GetEndpoint() uint32 { + if x != nil { + return x.Endpoint + } + return 0 +} + +func (x *USBURBRequest) GetDirectionIn() bool { + if x != nil { + return x.DirectionIn + } + return false +} + +func (x *USBURBRequest) GetTransferFlags() uint32 { + if x != nil { + return x.TransferFlags + } + return 0 +} + +func (x *USBURBRequest) GetSetup() []byte { + if x != nil { + return x.Setup + } + return nil +} + +func (x *USBURBRequest) GetTransferBufferLength() uint32 { + if x != nil { + return x.TransferBufferLength + } + return 0 +} + +func (x *USBURBRequest) GetOutData() []byte { + if x != nil { + return x.OutData + } + return nil +} + +func (x *USBURBRequest) GetNumberOfPackets() int32 { + if x != nil { + return x.NumberOfPackets + } + return 0 +} + +func (x *USBURBRequest) GetStartFrame() int32 { + if x != nil { + return x.StartFrame + } + return 0 +} + +func (x *USBURBRequest) GetInterval() int32 { + if x != nil { + return x.Interval + } + return 0 +} + +func (x *USBURBRequest) GetIsoPackets() []*USBIsoPacket { + if x != nil { + return x.IsoPackets + } + return nil +} + +type USBURBResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + DeviceId string `protobuf:"bytes,1,opt,name=deviceId,proto3" json:"deviceId,omitempty"` + Seq uint64 `protobuf:"varint,2,opt,name=seq,proto3" json:"seq,omitempty"` + Status int32 `protobuf:"varint,3,opt,name=status,proto3" json:"status,omitempty"` + ActualLength int32 `protobuf:"varint,4,opt,name=actualLength,proto3" json:"actualLength,omitempty"` + InData []byte `protobuf:"bytes,5,opt,name=inData,proto3" json:"inData,omitempty"` + IsoPackets []*USBIsoPacket `protobuf:"bytes,6,rep,name=isoPackets,proto3" json:"isoPackets,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *USBURBResponse) Reset() { + *x = USBURBResponse{} + mi := &file_daemon_started_service_proto_msgTypes[54] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *USBURBResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*USBURBResponse) ProtoMessage() {} + +func (x *USBURBResponse) ProtoReflect() protoreflect.Message { + mi := &file_daemon_started_service_proto_msgTypes[54] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use USBURBResponse.ProtoReflect.Descriptor instead. +func (*USBURBResponse) Descriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{54} +} + +func (x *USBURBResponse) GetDeviceId() string { + if x != nil { + return x.DeviceId + } + return "" +} + +func (x *USBURBResponse) GetSeq() uint64 { + if x != nil { + return x.Seq + } + return 0 +} + +func (x *USBURBResponse) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *USBURBResponse) GetActualLength() int32 { + if x != nil { + return x.ActualLength + } + return 0 +} + +func (x *USBURBResponse) GetInData() []byte { + if x != nil { + return x.InData + } + return nil +} + +func (x *USBURBResponse) GetIsoPackets() []*USBIsoPacket { + if x != nil { + return x.IsoPackets + } + return nil +} + +type USBIsoPacket struct { + state protoimpl.MessageState `protogen:"open.v1"` + Offset int32 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + Length int32 `protobuf:"varint,2,opt,name=length,proto3" json:"length,omitempty"` + ActualLength int32 `protobuf:"varint,3,opt,name=actualLength,proto3" json:"actualLength,omitempty"` + Status int32 `protobuf:"varint,4,opt,name=status,proto3" json:"status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *USBIsoPacket) Reset() { + *x = USBIsoPacket{} + mi := &file_daemon_started_service_proto_msgTypes[55] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *USBIsoPacket) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*USBIsoPacket) ProtoMessage() {} + +func (x *USBIsoPacket) ProtoReflect() protoreflect.Message { + mi := &file_daemon_started_service_proto_msgTypes[55] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use USBIsoPacket.ProtoReflect.Descriptor instead. +func (*USBIsoPacket) Descriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{55} +} + +func (x *USBIsoPacket) GetOffset() int32 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *USBIsoPacket) GetLength() int32 { + if x != nil { + return x.Length + } + return 0 +} + +func (x *USBIsoPacket) GetActualLength() int32 { + if x != nil { + return x.ActualLength + } + return 0 +} + +func (x *USBIsoPacket) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +type USBEndpointAbort struct { + state protoimpl.MessageState `protogen:"open.v1"` + DeviceId string `protobuf:"bytes,1,opt,name=deviceId,proto3" json:"deviceId,omitempty"` + Endpoint uint32 `protobuf:"varint,2,opt,name=endpoint,proto3" json:"endpoint,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *USBEndpointAbort) Reset() { + *x = USBEndpointAbort{} + mi := &file_daemon_started_service_proto_msgTypes[56] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *USBEndpointAbort) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*USBEndpointAbort) ProtoMessage() {} + +func (x *USBEndpointAbort) ProtoReflect() protoreflect.Message { + mi := &file_daemon_started_service_proto_msgTypes[56] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use USBEndpointAbort.ProtoReflect.Descriptor instead. +func (*USBEndpointAbort) Descriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{56} +} + +func (x *USBEndpointAbort) GetDeviceId() string { + if x != nil { + return x.DeviceId + } + return "" +} + +func (x *USBEndpointAbort) GetEndpoint() uint32 { + if x != nil { + return x.Endpoint + } + return 0 +} + +type USBError struct { + state protoimpl.MessageState `protogen:"open.v1"` + DeviceId string `protobuf:"bytes,1,opt,name=deviceId,proto3" json:"deviceId,omitempty"` + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *USBError) Reset() { + *x = USBError{} + mi := &file_daemon_started_service_proto_msgTypes[57] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *USBError) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*USBError) ProtoMessage() {} + +func (x *USBError) ProtoReflect() protoreflect.Message { + mi := &file_daemon_started_service_proto_msgTypes[57] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use USBError.ProtoReflect.Descriptor instead. +func (*USBError) Descriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{57} +} + +func (x *USBError) GetDeviceId() string { + if x != nil { + return x.DeviceId + } + return "" +} + +func (x *USBError) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +type USBIPServerStatusUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + Servers []*USBIPServerStatus `protobuf:"bytes,1,rep,name=servers,proto3" json:"servers,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *USBIPServerStatusUpdate) Reset() { + *x = USBIPServerStatusUpdate{} + mi := &file_daemon_started_service_proto_msgTypes[58] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *USBIPServerStatusUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*USBIPServerStatusUpdate) ProtoMessage() {} + +func (x *USBIPServerStatusUpdate) ProtoReflect() protoreflect.Message { + mi := &file_daemon_started_service_proto_msgTypes[58] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use USBIPServerStatusUpdate.ProtoReflect.Descriptor instead. +func (*USBIPServerStatusUpdate) Descriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{58} +} + +func (x *USBIPServerStatusUpdate) GetServers() []*USBIPServerStatus { + if x != nil { + return x.Servers + } + return nil +} + +type USBIPServerStatus struct { + state protoimpl.MessageState `protogen:"open.v1"` + ServerTag string `protobuf:"bytes,1,opt,name=serverTag,proto3" json:"serverTag,omitempty"` + Devices []*USBSharedDevice `protobuf:"bytes,2,rep,name=devices,proto3" json:"devices,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *USBIPServerStatus) Reset() { + *x = USBIPServerStatus{} + mi := &file_daemon_started_service_proto_msgTypes[59] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *USBIPServerStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*USBIPServerStatus) ProtoMessage() {} + +func (x *USBIPServerStatus) ProtoReflect() protoreflect.Message { + mi := &file_daemon_started_service_proto_msgTypes[59] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use USBIPServerStatus.ProtoReflect.Descriptor instead. +func (*USBIPServerStatus) Descriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{59} +} + +func (x *USBIPServerStatus) GetServerTag() string { + if x != nil { + return x.ServerTag + } + return "" +} + +func (x *USBIPServerStatus) GetDevices() []*USBSharedDevice { + if x != nil { + return x.Devices + } + return nil +} + +type USBSharedDevice struct { + state protoimpl.MessageState `protogen:"open.v1"` + Descriptor_ *USBDeviceDescriptor `protobuf:"bytes,1,opt,name=descriptor,proto3" json:"descriptor,omitempty"` + BusId string `protobuf:"bytes,2,opt,name=busId,proto3" json:"busId,omitempty"` + StableId string `protobuf:"bytes,3,opt,name=stableId,proto3" json:"stableId,omitempty"` + Backend USBBackend `protobuf:"varint,4,opt,name=backend,proto3,enum=daemon.USBBackend" json:"backend,omitempty"` + State USBDeviceState `protobuf:"varint,5,opt,name=state,proto3,enum=daemon.USBDeviceState" json:"state,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *USBSharedDevice) Reset() { + *x = USBSharedDevice{} + mi := &file_daemon_started_service_proto_msgTypes[60] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *USBSharedDevice) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*USBSharedDevice) ProtoMessage() {} + +func (x *USBSharedDevice) ProtoReflect() protoreflect.Message { + mi := &file_daemon_started_service_proto_msgTypes[60] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use USBSharedDevice.ProtoReflect.Descriptor instead. +func (*USBSharedDevice) Descriptor() ([]byte, []int) { + return file_daemon_started_service_proto_rawDescGZIP(), []int{60} +} + +func (x *USBSharedDevice) GetDescriptor_() *USBDeviceDescriptor { + if x != nil { + return x.Descriptor_ + } + return nil +} + +func (x *USBSharedDevice) GetBusId() string { + if x != nil { + return x.BusId + } + return "" +} + +func (x *USBSharedDevice) GetStableId() string { + if x != nil { + return x.StableId + } + return "" +} + +func (x *USBSharedDevice) GetBackend() USBBackend { + if x != nil { + return x.Backend + } + return USBBackend_USB_BACKEND_UNSPECIFIED +} + +func (x *USBSharedDevice) GetState() USBDeviceState { + if x != nil { + return x.State + } + return USBDeviceState_USB_DEVICE_STATE_IDLE +} + type Log_Message struct { state protoimpl.MessageState `protogen:"open.v1"` Level LogLevel `protobuf:"varint,1,opt,name=level,proto3,enum=daemon.LogLevel" json:"level,omitempty"` @@ -3388,7 +4628,7 @@ type Log_Message struct { func (x *Log_Message) Reset() { *x = Log_Message{} - mi := &file_daemon_started_service_proto_msgTypes[46] + mi := &file_daemon_started_service_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3400,7 +4640,7 @@ func (x *Log_Message) String() string { func (*Log_Message) ProtoMessage() {} func (x *Log_Message) ProtoReflect() protoreflect.Message { - mi := &file_daemon_started_service_proto_msgTypes[46] + mi := &file_daemon_started_service_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3693,7 +4933,104 @@ const file_daemon_started_service_proto_rawDesc = "" + "\x06signal\x18\x02 \x01(\tR\x06signal\x12\"\n" + "\ferrorMessage\x18\x03 \x01(\tR\ferrorMessage\"-\n" + "\x11TailscaleSSHError\x12\x18\n" + - "\amessage\x18\x01 \x01(\tR\amessage*U\n" + + "\amessage\x18\x01 \x01(\tR\amessage\"\xc1\x01\n" + + "\x12USBProviderMessage\x121\n" + + "\x06attach\x18\x01 \x01(\v2\x17.daemon.USBDeviceAttachH\x00R\x06attach\x121\n" + + "\x06detach\x18\x02 \x01(\v2\x17.daemon.USBDeviceDetachH\x00R\x06detach\x12:\n" + + "\vurbResponse\x18\x03 \x01(\v2\x16.daemon.USBURBResponseH\x00R\vurbResponseB\t\n" + + "\amessage\"\xe2\x01\n" + + "\x10USBServerMessage\x12.\n" + + "\x05ready\x18\x01 \x01(\v2\x16.daemon.USBDeviceReadyH\x00R\x05ready\x127\n" + + "\n" + + "urbRequest\x18\x02 \x01(\v2\x15.daemon.USBURBRequestH\x00R\n" + + "urbRequest\x120\n" + + "\x05abort\x18\x03 \x01(\v2\x18.daemon.USBEndpointAbortH\x00R\x05abort\x12(\n" + + "\x05error\x18\x04 \x01(\v2\x10.daemon.USBErrorH\x00R\x05errorB\t\n" + + "\amessage\"\x87\x04\n" + + "\x13USBDeviceDescriptor\x12\x1a\n" + + "\bdeviceId\x18\x01 \x01(\tR\bdeviceId\x12\x16\n" + + "\x06busNum\x18\x02 \x01(\rR\x06busNum\x12\x16\n" + + "\x06devNum\x18\x03 \x01(\rR\x06devNum\x12\x14\n" + + "\x05speed\x18\x04 \x01(\rR\x05speed\x12\x1a\n" + + "\bvendorId\x18\x05 \x01(\rR\bvendorId\x12\x1c\n" + + "\tproductId\x18\x06 \x01(\rR\tproductId\x12\x1c\n" + + "\tbcdDevice\x18\a \x01(\rR\tbcdDevice\x12 \n" + + "\vdeviceClass\x18\b \x01(\rR\vdeviceClass\x12&\n" + + "\x0edeviceSubClass\x18\t \x01(\rR\x0edeviceSubClass\x12&\n" + + "\x0edeviceProtocol\x18\n" + + " \x01(\rR\x0edeviceProtocol\x12.\n" + + "\x12configurationValue\x18\v \x01(\rR\x12configurationValue\x12,\n" + + "\x11numConfigurations\x18\f \x01(\rR\x11numConfigurations\x124\n" + + "\n" + + "interfaces\x18\r \x03(\v2\x14.daemon.USBInterfaceR\n" + + "interfaces\x12\x16\n" + + "\x06serial\x18\x0e \x01(\tR\x06serial\x12\x18\n" + + "\aproduct\x18\x0f \x01(\tR\aproduct\"l\n" + + "\x0fUSBDeviceAttach\x12\x1c\n" + + "\tserverTag\x18\x01 \x01(\tR\tserverTag\x12;\n" + + "\n" + + "descriptor\x18\x02 \x01(\v2\x1b.daemon.USBDeviceDescriptorR\n" + + "descriptor\"\x92\x01\n" + + "\fUSBInterface\x12&\n" + + "\x0einterfaceClass\x18\x01 \x01(\rR\x0einterfaceClass\x12,\n" + + "\x11interfaceSubClass\x18\x02 \x01(\rR\x11interfaceSubClass\x12,\n" + + "\x11interfaceProtocol\x18\x03 \x01(\rR\x11interfaceProtocol\"-\n" + + "\x0fUSBDeviceDetach\x12\x1a\n" + + "\bdeviceId\x18\x01 \x01(\tR\bdeviceId\"B\n" + + "\x0eUSBDeviceReady\x12\x1a\n" + + "\bdeviceId\x18\x01 \x01(\tR\bdeviceId\x12\x14\n" + + "\x05busId\x18\x02 \x01(\tR\x05busId\"\xa1\x03\n" + + "\rUSBURBRequest\x12\x1a\n" + + "\bdeviceId\x18\x01 \x01(\tR\bdeviceId\x12\x10\n" + + "\x03seq\x18\x02 \x01(\x04R\x03seq\x12\x1a\n" + + "\bendpoint\x18\x03 \x01(\rR\bendpoint\x12 \n" + + "\vdirectionIn\x18\x04 \x01(\bR\vdirectionIn\x12$\n" + + "\rtransferFlags\x18\x05 \x01(\rR\rtransferFlags\x12\x14\n" + + "\x05setup\x18\x06 \x01(\fR\x05setup\x122\n" + + "\x14transferBufferLength\x18\a \x01(\rR\x14transferBufferLength\x12\x18\n" + + "\aoutData\x18\b \x01(\fR\aoutData\x12(\n" + + "\x0fnumberOfPackets\x18\t \x01(\x05R\x0fnumberOfPackets\x12\x1e\n" + + "\n" + + "startFrame\x18\n" + + " \x01(\x05R\n" + + "startFrame\x12\x1a\n" + + "\binterval\x18\v \x01(\x05R\binterval\x124\n" + + "\n" + + "isoPackets\x18\f \x03(\v2\x14.daemon.USBIsoPacketR\n" + + "isoPackets\"\xc8\x01\n" + + "\x0eUSBURBResponse\x12\x1a\n" + + "\bdeviceId\x18\x01 \x01(\tR\bdeviceId\x12\x10\n" + + "\x03seq\x18\x02 \x01(\x04R\x03seq\x12\x16\n" + + "\x06status\x18\x03 \x01(\x05R\x06status\x12\"\n" + + "\factualLength\x18\x04 \x01(\x05R\factualLength\x12\x16\n" + + "\x06inData\x18\x05 \x01(\fR\x06inData\x124\n" + + "\n" + + "isoPackets\x18\x06 \x03(\v2\x14.daemon.USBIsoPacketR\n" + + "isoPackets\"z\n" + + "\fUSBIsoPacket\x12\x16\n" + + "\x06offset\x18\x01 \x01(\x05R\x06offset\x12\x16\n" + + "\x06length\x18\x02 \x01(\x05R\x06length\x12\"\n" + + "\factualLength\x18\x03 \x01(\x05R\factualLength\x12\x16\n" + + "\x06status\x18\x04 \x01(\x05R\x06status\"J\n" + + "\x10USBEndpointAbort\x12\x1a\n" + + "\bdeviceId\x18\x01 \x01(\tR\bdeviceId\x12\x1a\n" + + "\bendpoint\x18\x02 \x01(\rR\bendpoint\"@\n" + + "\bUSBError\x12\x1a\n" + + "\bdeviceId\x18\x01 \x01(\tR\bdeviceId\x12\x18\n" + + "\amessage\x18\x02 \x01(\tR\amessage\"N\n" + + "\x17USBIPServerStatusUpdate\x123\n" + + "\aservers\x18\x01 \x03(\v2\x19.daemon.USBIPServerStatusR\aservers\"d\n" + + "\x11USBIPServerStatus\x12\x1c\n" + + "\tserverTag\x18\x01 \x01(\tR\tserverTag\x121\n" + + "\adevices\x18\x02 \x03(\v2\x17.daemon.USBSharedDeviceR\adevices\"\xdc\x01\n" + + "\x0fUSBSharedDevice\x12;\n" + + "\n" + + "descriptor\x18\x01 \x01(\v2\x1b.daemon.USBDeviceDescriptorR\n" + + "descriptor\x12\x14\n" + + "\x05busId\x18\x02 \x01(\tR\x05busId\x12\x1a\n" + + "\bstableId\x18\x03 \x01(\tR\bstableId\x12,\n" + + "\abackend\x18\x04 \x01(\x0e2\x12.daemon.USBBackendR\abackend\x12,\n" + + "\x05state\x18\x05 \x01(\x0e2\x16.daemon.USBDeviceStateR\x05state*U\n" + "\bLogLevel\x12\t\n" + "\x05PANIC\x10\x00\x12\t\n" + "\x05FATAL\x10\x01\x12\t\n" + @@ -3705,7 +5042,18 @@ const file_daemon_started_service_proto_rawDesc = "" + "\x13ConnectionEventType\x12\x18\n" + "\x14CONNECTION_EVENT_NEW\x10\x00\x12\x1b\n" + "\x17CONNECTION_EVENT_UPDATE\x10\x01\x12\x1b\n" + - "\x17CONNECTION_EVENT_CLOSED\x10\x022\xee\x0f\n" + + "\x17CONNECTION_EVENT_CLOSED\x10\x02*l\n" + + "\x0eUSBDeviceState\x12\x19\n" + + "\x15USB_DEVICE_STATE_IDLE\x10\x00\x12\x1d\n" + + "\x19USB_DEVICE_STATE_ATTACHED\x10\x01\x12 \n" + + "\x1cUSB_DEVICE_STATE_UNAVAILABLE\x10\x02*\x9e\x01\n" + + "\n" + + "USBBackend\x12\x1b\n" + + "\x17USB_BACKEND_UNSPECIFIED\x10\x00\x12\x1b\n" + + "\x17USB_BACKEND_LINUX_SYSFS\x10\x01\x12\x17\n" + + "\x13USB_BACKEND_DYNAMIC\x10\x02\x12\x1c\n" + + "\x18USB_BACKEND_DARWIN_IOKIT\x10\x03\x12\x1f\n" + + "\x1bUSB_BACKEND_WINDOWS_VBOXUSB\x10\x042\xd4\x10\n" + "\x0eStartedService\x127\n" + "\n" + "GetVersion\x12\x16.google.protobuf.Empty\x1a\x0f.daemon.Version\"\x00\x12K\n" + @@ -3720,8 +5068,7 @@ const file_daemon_started_service_proto_rawDesc = "" + "\fSetClashMode\x12\x11.daemon.ClashMode\x1a\x16.google.protobuf.Empty\"\x00\x12;\n" + "\aURLTest\x12\x16.daemon.URLTestRequest\x1a\x16.google.protobuf.Empty\"\x00\x12I\n" + "\x0eSelectOutbound\x12\x1d.daemon.SelectOutboundRequest\x1a\x16.google.protobuf.Empty\"\x00\x12I\n" + - "\x0eSetGroupExpand\x12\x1d.daemon.SetGroupExpandRequest\x1a\x16.google.protobuf.Empty\"\x00\x12D\n" + - "\x10TriggerOOMReport\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\"\x00\x12Y\n" + + "\x0eSetGroupExpand\x12\x1d.daemon.SetGroupExpandRequest\x1a\x16.google.protobuf.Empty\"\x00\x12Y\n" + "\x14SubscribeConnections\x12#.daemon.SubscribeConnectionsRequest\x1a\x18.daemon.ConnectionEvents\"\x000\x01\x12K\n" + "\x0fCloseConnection\x12\x1e.daemon.CloseConnectionRequest\x1a\x16.google.protobuf.Empty\"\x00\x12G\n" + "\x13CloseAllConnections\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\"\x00\x12M\n" + @@ -3734,7 +5081,9 @@ const file_daemon_started_service_proto_rawDesc = "" + "\x12StartTailscalePing\x12\x1c.daemon.TailscalePingRequest\x1a\x1d.daemon.TailscalePingResponse\"\x000\x01\x12U\n" + "\x14SetTailscaleExitNode\x12#.daemon.SetTailscaleExitNodeRequest\x1a\x16.google.protobuf.Empty\"\x00\x12K\n" + "\x0fTailscaleLogout\x12\x1e.daemon.TailscaleLogoutRequest\x1a\x16.google.protobuf.Empty\"\x00\x12f\n" + - "\x18StartTailscaleSSHSession\x12!.daemon.TailscaleSSHClientMessage\x1a!.daemon.TailscaleSSHServerMessage\"\x00(\x010\x01B%Z#github.com/sagernet/sing-box/daemonb\x06proto3" + "\x18StartTailscaleSSHSession\x12!.daemon.TailscaleSSHClientMessage\x1a!.daemon.TailscaleSSHServerMessage\"\x00(\x010\x01\x12O\n" + + "\x11ProvideUSBDevices\x12\x1a.daemon.USBProviderMessage\x1a\x18.daemon.USBServerMessage\"\x00(\x010\x01\x12Y\n" + + "\x1aSubscribeUSBIPServerStatus\x12\x16.google.protobuf.Empty\x1a\x1f.daemon.USBIPServerStatusUpdate\"\x000\x01B%Z#github.com/sagernet/sing-box/daemonb\x06proto3" var ( file_daemon_started_service_proto_rawDescOnce sync.Once @@ -3749,148 +5098,183 @@ func file_daemon_started_service_proto_rawDescGZIP() []byte { } var ( - file_daemon_started_service_proto_enumTypes = make([]protoimpl.EnumInfo, 3) - file_daemon_started_service_proto_msgTypes = make([]protoimpl.MessageInfo, 47) + file_daemon_started_service_proto_enumTypes = make([]protoimpl.EnumInfo, 5) + file_daemon_started_service_proto_msgTypes = make([]protoimpl.MessageInfo, 62) file_daemon_started_service_proto_goTypes = []any{ (LogLevel)(0), // 0: daemon.LogLevel (ConnectionEventType)(0), // 1: daemon.ConnectionEventType - (ServiceStatus_Type)(0), // 2: daemon.ServiceStatus.Type - (*Version)(nil), // 3: daemon.Version - (*ServiceStatus)(nil), // 4: daemon.ServiceStatus - (*SubscribeStatusRequest)(nil), // 5: daemon.SubscribeStatusRequest - (*Log)(nil), // 6: daemon.Log - (*DefaultLogLevel)(nil), // 7: daemon.DefaultLogLevel - (*Status)(nil), // 8: daemon.Status - (*Groups)(nil), // 9: daemon.Groups - (*Group)(nil), // 10: daemon.Group - (*GroupItem)(nil), // 11: daemon.GroupItem - (*URLTestRequest)(nil), // 12: daemon.URLTestRequest - (*SelectOutboundRequest)(nil), // 13: daemon.SelectOutboundRequest - (*SetGroupExpandRequest)(nil), // 14: daemon.SetGroupExpandRequest - (*ClashMode)(nil), // 15: daemon.ClashMode - (*ClashModeStatus)(nil), // 16: daemon.ClashModeStatus - (*SubscribeConnectionsRequest)(nil), // 17: daemon.SubscribeConnectionsRequest - (*ConnectionEvent)(nil), // 18: daemon.ConnectionEvent - (*ConnectionEvents)(nil), // 19: daemon.ConnectionEvents - (*Connection)(nil), // 20: daemon.Connection - (*ProcessInfo)(nil), // 21: daemon.ProcessInfo - (*CloseConnectionRequest)(nil), // 22: daemon.CloseConnectionRequest - (*DeprecatedWarnings)(nil), // 23: daemon.DeprecatedWarnings - (*DeprecatedWarning)(nil), // 24: daemon.DeprecatedWarning - (*StartedAt)(nil), // 25: daemon.StartedAt - (*OutboundList)(nil), // 26: daemon.OutboundList - (*NetworkQualityTestRequest)(nil), // 27: daemon.NetworkQualityTestRequest - (*NetworkQualityTestProgress)(nil), // 28: daemon.NetworkQualityTestProgress - (*STUNTestRequest)(nil), // 29: daemon.STUNTestRequest - (*STUNTestProgress)(nil), // 30: daemon.STUNTestProgress - (*TailscaleStatusUpdate)(nil), // 31: daemon.TailscaleStatusUpdate - (*TailscaleEndpointStatus)(nil), // 32: daemon.TailscaleEndpointStatus - (*TailscaleUserGroup)(nil), // 33: daemon.TailscaleUserGroup - (*TailscalePeer)(nil), // 34: daemon.TailscalePeer - (*TailscalePingRequest)(nil), // 35: daemon.TailscalePingRequest - (*TailscalePingResponse)(nil), // 36: daemon.TailscalePingResponse - (*SetTailscaleExitNodeRequest)(nil), // 37: daemon.SetTailscaleExitNodeRequest - (*TailscaleLogoutRequest)(nil), // 38: daemon.TailscaleLogoutRequest - (*TailscaleSSHClientMessage)(nil), // 39: daemon.TailscaleSSHClientMessage - (*TailscaleSSHStart)(nil), // 40: daemon.TailscaleSSHStart - (*TailscaleSSHInput)(nil), // 41: daemon.TailscaleSSHInput - (*TailscaleSSHResize)(nil), // 42: daemon.TailscaleSSHResize - (*TailscaleSSHServerMessage)(nil), // 43: daemon.TailscaleSSHServerMessage - (*TailscaleSSHAuthBanner)(nil), // 44: daemon.TailscaleSSHAuthBanner - (*TailscaleSSHReady)(nil), // 45: daemon.TailscaleSSHReady - (*TailscaleSSHOutput)(nil), // 46: daemon.TailscaleSSHOutput - (*TailscaleSSHExit)(nil), // 47: daemon.TailscaleSSHExit - (*TailscaleSSHError)(nil), // 48: daemon.TailscaleSSHError - (*Log_Message)(nil), // 49: daemon.Log.Message - (*emptypb.Empty)(nil), // 50: google.protobuf.Empty + (USBDeviceState)(0), // 2: daemon.USBDeviceState + (USBBackend)(0), // 3: daemon.USBBackend + (ServiceStatus_Type)(0), // 4: daemon.ServiceStatus.Type + (*Version)(nil), // 5: daemon.Version + (*ServiceStatus)(nil), // 6: daemon.ServiceStatus + (*SubscribeStatusRequest)(nil), // 7: daemon.SubscribeStatusRequest + (*Log)(nil), // 8: daemon.Log + (*DefaultLogLevel)(nil), // 9: daemon.DefaultLogLevel + (*Status)(nil), // 10: daemon.Status + (*Groups)(nil), // 11: daemon.Groups + (*Group)(nil), // 12: daemon.Group + (*GroupItem)(nil), // 13: daemon.GroupItem + (*URLTestRequest)(nil), // 14: daemon.URLTestRequest + (*SelectOutboundRequest)(nil), // 15: daemon.SelectOutboundRequest + (*SetGroupExpandRequest)(nil), // 16: daemon.SetGroupExpandRequest + (*ClashMode)(nil), // 17: daemon.ClashMode + (*ClashModeStatus)(nil), // 18: daemon.ClashModeStatus + (*SubscribeConnectionsRequest)(nil), // 19: daemon.SubscribeConnectionsRequest + (*ConnectionEvent)(nil), // 20: daemon.ConnectionEvent + (*ConnectionEvents)(nil), // 21: daemon.ConnectionEvents + (*Connection)(nil), // 22: daemon.Connection + (*ProcessInfo)(nil), // 23: daemon.ProcessInfo + (*CloseConnectionRequest)(nil), // 24: daemon.CloseConnectionRequest + (*DeprecatedWarnings)(nil), // 25: daemon.DeprecatedWarnings + (*DeprecatedWarning)(nil), // 26: daemon.DeprecatedWarning + (*StartedAt)(nil), // 27: daemon.StartedAt + (*OutboundList)(nil), // 28: daemon.OutboundList + (*NetworkQualityTestRequest)(nil), // 29: daemon.NetworkQualityTestRequest + (*NetworkQualityTestProgress)(nil), // 30: daemon.NetworkQualityTestProgress + (*STUNTestRequest)(nil), // 31: daemon.STUNTestRequest + (*STUNTestProgress)(nil), // 32: daemon.STUNTestProgress + (*TailscaleStatusUpdate)(nil), // 33: daemon.TailscaleStatusUpdate + (*TailscaleEndpointStatus)(nil), // 34: daemon.TailscaleEndpointStatus + (*TailscaleUserGroup)(nil), // 35: daemon.TailscaleUserGroup + (*TailscalePeer)(nil), // 36: daemon.TailscalePeer + (*TailscalePingRequest)(nil), // 37: daemon.TailscalePingRequest + (*TailscalePingResponse)(nil), // 38: daemon.TailscalePingResponse + (*SetTailscaleExitNodeRequest)(nil), // 39: daemon.SetTailscaleExitNodeRequest + (*TailscaleLogoutRequest)(nil), // 40: daemon.TailscaleLogoutRequest + (*TailscaleSSHClientMessage)(nil), // 41: daemon.TailscaleSSHClientMessage + (*TailscaleSSHStart)(nil), // 42: daemon.TailscaleSSHStart + (*TailscaleSSHInput)(nil), // 43: daemon.TailscaleSSHInput + (*TailscaleSSHResize)(nil), // 44: daemon.TailscaleSSHResize + (*TailscaleSSHServerMessage)(nil), // 45: daemon.TailscaleSSHServerMessage + (*TailscaleSSHAuthBanner)(nil), // 46: daemon.TailscaleSSHAuthBanner + (*TailscaleSSHReady)(nil), // 47: daemon.TailscaleSSHReady + (*TailscaleSSHOutput)(nil), // 48: daemon.TailscaleSSHOutput + (*TailscaleSSHExit)(nil), // 49: daemon.TailscaleSSHExit + (*TailscaleSSHError)(nil), // 50: daemon.TailscaleSSHError + (*USBProviderMessage)(nil), // 51: daemon.USBProviderMessage + (*USBServerMessage)(nil), // 52: daemon.USBServerMessage + (*USBDeviceDescriptor)(nil), // 53: daemon.USBDeviceDescriptor + (*USBDeviceAttach)(nil), // 54: daemon.USBDeviceAttach + (*USBInterface)(nil), // 55: daemon.USBInterface + (*USBDeviceDetach)(nil), // 56: daemon.USBDeviceDetach + (*USBDeviceReady)(nil), // 57: daemon.USBDeviceReady + (*USBURBRequest)(nil), // 58: daemon.USBURBRequest + (*USBURBResponse)(nil), // 59: daemon.USBURBResponse + (*USBIsoPacket)(nil), // 60: daemon.USBIsoPacket + (*USBEndpointAbort)(nil), // 61: daemon.USBEndpointAbort + (*USBError)(nil), // 62: daemon.USBError + (*USBIPServerStatusUpdate)(nil), // 63: daemon.USBIPServerStatusUpdate + (*USBIPServerStatus)(nil), // 64: daemon.USBIPServerStatus + (*USBSharedDevice)(nil), // 65: daemon.USBSharedDevice + (*Log_Message)(nil), // 66: daemon.Log.Message + (*emptypb.Empty)(nil), // 67: google.protobuf.Empty } ) var file_daemon_started_service_proto_depIdxs = []int32{ - 2, // 0: daemon.ServiceStatus.status:type_name -> daemon.ServiceStatus.Type - 49, // 1: daemon.Log.messages:type_name -> daemon.Log.Message + 4, // 0: daemon.ServiceStatus.status:type_name -> daemon.ServiceStatus.Type + 66, // 1: daemon.Log.messages:type_name -> daemon.Log.Message 0, // 2: daemon.DefaultLogLevel.level:type_name -> daemon.LogLevel - 10, // 3: daemon.Groups.group:type_name -> daemon.Group - 11, // 4: daemon.Group.items:type_name -> daemon.GroupItem + 12, // 3: daemon.Groups.group:type_name -> daemon.Group + 13, // 4: daemon.Group.items:type_name -> daemon.GroupItem 1, // 5: daemon.ConnectionEvent.type:type_name -> daemon.ConnectionEventType - 20, // 6: daemon.ConnectionEvent.connection:type_name -> daemon.Connection - 18, // 7: daemon.ConnectionEvents.events:type_name -> daemon.ConnectionEvent - 21, // 8: daemon.Connection.processInfo:type_name -> daemon.ProcessInfo - 24, // 9: daemon.DeprecatedWarnings.warnings:type_name -> daemon.DeprecatedWarning - 11, // 10: daemon.OutboundList.outbounds:type_name -> daemon.GroupItem - 32, // 11: daemon.TailscaleStatusUpdate.endpoints:type_name -> daemon.TailscaleEndpointStatus - 34, // 12: daemon.TailscaleEndpointStatus.self:type_name -> daemon.TailscalePeer - 33, // 13: daemon.TailscaleEndpointStatus.userGroups:type_name -> daemon.TailscaleUserGroup - 34, // 14: daemon.TailscaleEndpointStatus.exitNode:type_name -> daemon.TailscalePeer - 34, // 15: daemon.TailscaleUserGroup.peers:type_name -> daemon.TailscalePeer - 40, // 16: daemon.TailscaleSSHClientMessage.start:type_name -> daemon.TailscaleSSHStart - 41, // 17: daemon.TailscaleSSHClientMessage.input:type_name -> daemon.TailscaleSSHInput - 42, // 18: daemon.TailscaleSSHClientMessage.resize:type_name -> daemon.TailscaleSSHResize - 44, // 19: daemon.TailscaleSSHServerMessage.authBanner:type_name -> daemon.TailscaleSSHAuthBanner - 45, // 20: daemon.TailscaleSSHServerMessage.ready:type_name -> daemon.TailscaleSSHReady - 46, // 21: daemon.TailscaleSSHServerMessage.output:type_name -> daemon.TailscaleSSHOutput - 47, // 22: daemon.TailscaleSSHServerMessage.exit:type_name -> daemon.TailscaleSSHExit - 48, // 23: daemon.TailscaleSSHServerMessage.error:type_name -> daemon.TailscaleSSHError - 0, // 24: daemon.Log.Message.level:type_name -> daemon.LogLevel - 50, // 25: daemon.StartedService.GetVersion:input_type -> google.protobuf.Empty - 50, // 26: daemon.StartedService.SubscribeServiceStatus:input_type -> google.protobuf.Empty - 50, // 27: daemon.StartedService.SubscribeLog:input_type -> google.protobuf.Empty - 50, // 28: daemon.StartedService.GetDefaultLogLevel:input_type -> google.protobuf.Empty - 50, // 29: daemon.StartedService.ClearLogs:input_type -> google.protobuf.Empty - 5, // 30: daemon.StartedService.SubscribeStatus:input_type -> daemon.SubscribeStatusRequest - 50, // 31: daemon.StartedService.SubscribeGroups:input_type -> google.protobuf.Empty - 50, // 32: daemon.StartedService.GetClashModeStatus:input_type -> google.protobuf.Empty - 50, // 33: daemon.StartedService.SubscribeClashMode:input_type -> google.protobuf.Empty - 15, // 34: daemon.StartedService.SetClashMode:input_type -> daemon.ClashMode - 12, // 35: daemon.StartedService.URLTest:input_type -> daemon.URLTestRequest - 13, // 36: daemon.StartedService.SelectOutbound:input_type -> daemon.SelectOutboundRequest - 14, // 37: daemon.StartedService.SetGroupExpand:input_type -> daemon.SetGroupExpandRequest - 50, // 38: daemon.StartedService.TriggerOOMReport:input_type -> google.protobuf.Empty - 17, // 39: daemon.StartedService.SubscribeConnections:input_type -> daemon.SubscribeConnectionsRequest - 22, // 40: daemon.StartedService.CloseConnection:input_type -> daemon.CloseConnectionRequest - 50, // 41: daemon.StartedService.CloseAllConnections:input_type -> google.protobuf.Empty - 50, // 42: daemon.StartedService.GetDeprecatedWarnings:input_type -> google.protobuf.Empty - 50, // 43: daemon.StartedService.GetStartedAt:input_type -> google.protobuf.Empty - 50, // 44: daemon.StartedService.SubscribeOutbounds:input_type -> google.protobuf.Empty - 27, // 45: daemon.StartedService.StartNetworkQualityTest:input_type -> daemon.NetworkQualityTestRequest - 29, // 46: daemon.StartedService.StartSTUNTest:input_type -> daemon.STUNTestRequest - 50, // 47: daemon.StartedService.SubscribeTailscaleStatus:input_type -> google.protobuf.Empty - 35, // 48: daemon.StartedService.StartTailscalePing:input_type -> daemon.TailscalePingRequest - 37, // 49: daemon.StartedService.SetTailscaleExitNode:input_type -> daemon.SetTailscaleExitNodeRequest - 38, // 50: daemon.StartedService.TailscaleLogout:input_type -> daemon.TailscaleLogoutRequest - 39, // 51: daemon.StartedService.StartTailscaleSSHSession:input_type -> daemon.TailscaleSSHClientMessage - 3, // 52: daemon.StartedService.GetVersion:output_type -> daemon.Version - 4, // 53: daemon.StartedService.SubscribeServiceStatus:output_type -> daemon.ServiceStatus - 6, // 54: daemon.StartedService.SubscribeLog:output_type -> daemon.Log - 7, // 55: daemon.StartedService.GetDefaultLogLevel:output_type -> daemon.DefaultLogLevel - 50, // 56: daemon.StartedService.ClearLogs:output_type -> google.protobuf.Empty - 8, // 57: daemon.StartedService.SubscribeStatus:output_type -> daemon.Status - 9, // 58: daemon.StartedService.SubscribeGroups:output_type -> daemon.Groups - 16, // 59: daemon.StartedService.GetClashModeStatus:output_type -> daemon.ClashModeStatus - 15, // 60: daemon.StartedService.SubscribeClashMode:output_type -> daemon.ClashMode - 50, // 61: daemon.StartedService.SetClashMode:output_type -> google.protobuf.Empty - 50, // 62: daemon.StartedService.URLTest:output_type -> google.protobuf.Empty - 50, // 63: daemon.StartedService.SelectOutbound:output_type -> google.protobuf.Empty - 50, // 64: daemon.StartedService.SetGroupExpand:output_type -> google.protobuf.Empty - 50, // 65: daemon.StartedService.TriggerOOMReport:output_type -> google.protobuf.Empty - 19, // 66: daemon.StartedService.SubscribeConnections:output_type -> daemon.ConnectionEvents - 50, // 67: daemon.StartedService.CloseConnection:output_type -> google.protobuf.Empty - 50, // 68: daemon.StartedService.CloseAllConnections:output_type -> google.protobuf.Empty - 23, // 69: daemon.StartedService.GetDeprecatedWarnings:output_type -> daemon.DeprecatedWarnings - 25, // 70: daemon.StartedService.GetStartedAt:output_type -> daemon.StartedAt - 26, // 71: daemon.StartedService.SubscribeOutbounds:output_type -> daemon.OutboundList - 28, // 72: daemon.StartedService.StartNetworkQualityTest:output_type -> daemon.NetworkQualityTestProgress - 30, // 73: daemon.StartedService.StartSTUNTest:output_type -> daemon.STUNTestProgress - 31, // 74: daemon.StartedService.SubscribeTailscaleStatus:output_type -> daemon.TailscaleStatusUpdate - 36, // 75: daemon.StartedService.StartTailscalePing:output_type -> daemon.TailscalePingResponse - 50, // 76: daemon.StartedService.SetTailscaleExitNode:output_type -> google.protobuf.Empty - 50, // 77: daemon.StartedService.TailscaleLogout:output_type -> google.protobuf.Empty - 43, // 78: daemon.StartedService.StartTailscaleSSHSession:output_type -> daemon.TailscaleSSHServerMessage - 52, // [52:79] is the sub-list for method output_type - 25, // [25:52] is the sub-list for method input_type - 25, // [25:25] is the sub-list for extension type_name - 25, // [25:25] is the sub-list for extension extendee - 0, // [0:25] is the sub-list for field type_name + 22, // 6: daemon.ConnectionEvent.connection:type_name -> daemon.Connection + 20, // 7: daemon.ConnectionEvents.events:type_name -> daemon.ConnectionEvent + 23, // 8: daemon.Connection.processInfo:type_name -> daemon.ProcessInfo + 26, // 9: daemon.DeprecatedWarnings.warnings:type_name -> daemon.DeprecatedWarning + 13, // 10: daemon.OutboundList.outbounds:type_name -> daemon.GroupItem + 34, // 11: daemon.TailscaleStatusUpdate.endpoints:type_name -> daemon.TailscaleEndpointStatus + 36, // 12: daemon.TailscaleEndpointStatus.self:type_name -> daemon.TailscalePeer + 35, // 13: daemon.TailscaleEndpointStatus.userGroups:type_name -> daemon.TailscaleUserGroup + 36, // 14: daemon.TailscaleEndpointStatus.exitNode:type_name -> daemon.TailscalePeer + 36, // 15: daemon.TailscaleUserGroup.peers:type_name -> daemon.TailscalePeer + 42, // 16: daemon.TailscaleSSHClientMessage.start:type_name -> daemon.TailscaleSSHStart + 43, // 17: daemon.TailscaleSSHClientMessage.input:type_name -> daemon.TailscaleSSHInput + 44, // 18: daemon.TailscaleSSHClientMessage.resize:type_name -> daemon.TailscaleSSHResize + 46, // 19: daemon.TailscaleSSHServerMessage.authBanner:type_name -> daemon.TailscaleSSHAuthBanner + 47, // 20: daemon.TailscaleSSHServerMessage.ready:type_name -> daemon.TailscaleSSHReady + 48, // 21: daemon.TailscaleSSHServerMessage.output:type_name -> daemon.TailscaleSSHOutput + 49, // 22: daemon.TailscaleSSHServerMessage.exit:type_name -> daemon.TailscaleSSHExit + 50, // 23: daemon.TailscaleSSHServerMessage.error:type_name -> daemon.TailscaleSSHError + 54, // 24: daemon.USBProviderMessage.attach:type_name -> daemon.USBDeviceAttach + 56, // 25: daemon.USBProviderMessage.detach:type_name -> daemon.USBDeviceDetach + 59, // 26: daemon.USBProviderMessage.urbResponse:type_name -> daemon.USBURBResponse + 57, // 27: daemon.USBServerMessage.ready:type_name -> daemon.USBDeviceReady + 58, // 28: daemon.USBServerMessage.urbRequest:type_name -> daemon.USBURBRequest + 61, // 29: daemon.USBServerMessage.abort:type_name -> daemon.USBEndpointAbort + 62, // 30: daemon.USBServerMessage.error:type_name -> daemon.USBError + 55, // 31: daemon.USBDeviceDescriptor.interfaces:type_name -> daemon.USBInterface + 53, // 32: daemon.USBDeviceAttach.descriptor:type_name -> daemon.USBDeviceDescriptor + 60, // 33: daemon.USBURBRequest.isoPackets:type_name -> daemon.USBIsoPacket + 60, // 34: daemon.USBURBResponse.isoPackets:type_name -> daemon.USBIsoPacket + 64, // 35: daemon.USBIPServerStatusUpdate.servers:type_name -> daemon.USBIPServerStatus + 65, // 36: daemon.USBIPServerStatus.devices:type_name -> daemon.USBSharedDevice + 53, // 37: daemon.USBSharedDevice.descriptor:type_name -> daemon.USBDeviceDescriptor + 3, // 38: daemon.USBSharedDevice.backend:type_name -> daemon.USBBackend + 2, // 39: daemon.USBSharedDevice.state:type_name -> daemon.USBDeviceState + 0, // 40: daemon.Log.Message.level:type_name -> daemon.LogLevel + 67, // 41: daemon.StartedService.GetVersion:input_type -> google.protobuf.Empty + 67, // 42: daemon.StartedService.SubscribeServiceStatus:input_type -> google.protobuf.Empty + 67, // 43: daemon.StartedService.SubscribeLog:input_type -> google.protobuf.Empty + 67, // 44: daemon.StartedService.GetDefaultLogLevel:input_type -> google.protobuf.Empty + 67, // 45: daemon.StartedService.ClearLogs:input_type -> google.protobuf.Empty + 7, // 46: daemon.StartedService.SubscribeStatus:input_type -> daemon.SubscribeStatusRequest + 67, // 47: daemon.StartedService.SubscribeGroups:input_type -> google.protobuf.Empty + 67, // 48: daemon.StartedService.GetClashModeStatus:input_type -> google.protobuf.Empty + 67, // 49: daemon.StartedService.SubscribeClashMode:input_type -> google.protobuf.Empty + 17, // 50: daemon.StartedService.SetClashMode:input_type -> daemon.ClashMode + 14, // 51: daemon.StartedService.URLTest:input_type -> daemon.URLTestRequest + 15, // 52: daemon.StartedService.SelectOutbound:input_type -> daemon.SelectOutboundRequest + 16, // 53: daemon.StartedService.SetGroupExpand:input_type -> daemon.SetGroupExpandRequest + 19, // 54: daemon.StartedService.SubscribeConnections:input_type -> daemon.SubscribeConnectionsRequest + 24, // 55: daemon.StartedService.CloseConnection:input_type -> daemon.CloseConnectionRequest + 67, // 56: daemon.StartedService.CloseAllConnections:input_type -> google.protobuf.Empty + 67, // 57: daemon.StartedService.GetDeprecatedWarnings:input_type -> google.protobuf.Empty + 67, // 58: daemon.StartedService.GetStartedAt:input_type -> google.protobuf.Empty + 67, // 59: daemon.StartedService.SubscribeOutbounds:input_type -> google.protobuf.Empty + 29, // 60: daemon.StartedService.StartNetworkQualityTest:input_type -> daemon.NetworkQualityTestRequest + 31, // 61: daemon.StartedService.StartSTUNTest:input_type -> daemon.STUNTestRequest + 67, // 62: daemon.StartedService.SubscribeTailscaleStatus:input_type -> google.protobuf.Empty + 37, // 63: daemon.StartedService.StartTailscalePing:input_type -> daemon.TailscalePingRequest + 39, // 64: daemon.StartedService.SetTailscaleExitNode:input_type -> daemon.SetTailscaleExitNodeRequest + 40, // 65: daemon.StartedService.TailscaleLogout:input_type -> daemon.TailscaleLogoutRequest + 41, // 66: daemon.StartedService.StartTailscaleSSHSession:input_type -> daemon.TailscaleSSHClientMessage + 51, // 67: daemon.StartedService.ProvideUSBDevices:input_type -> daemon.USBProviderMessage + 67, // 68: daemon.StartedService.SubscribeUSBIPServerStatus:input_type -> google.protobuf.Empty + 5, // 69: daemon.StartedService.GetVersion:output_type -> daemon.Version + 6, // 70: daemon.StartedService.SubscribeServiceStatus:output_type -> daemon.ServiceStatus + 8, // 71: daemon.StartedService.SubscribeLog:output_type -> daemon.Log + 9, // 72: daemon.StartedService.GetDefaultLogLevel:output_type -> daemon.DefaultLogLevel + 67, // 73: daemon.StartedService.ClearLogs:output_type -> google.protobuf.Empty + 10, // 74: daemon.StartedService.SubscribeStatus:output_type -> daemon.Status + 11, // 75: daemon.StartedService.SubscribeGroups:output_type -> daemon.Groups + 18, // 76: daemon.StartedService.GetClashModeStatus:output_type -> daemon.ClashModeStatus + 17, // 77: daemon.StartedService.SubscribeClashMode:output_type -> daemon.ClashMode + 67, // 78: daemon.StartedService.SetClashMode:output_type -> google.protobuf.Empty + 67, // 79: daemon.StartedService.URLTest:output_type -> google.protobuf.Empty + 67, // 80: daemon.StartedService.SelectOutbound:output_type -> google.protobuf.Empty + 67, // 81: daemon.StartedService.SetGroupExpand:output_type -> google.protobuf.Empty + 21, // 82: daemon.StartedService.SubscribeConnections:output_type -> daemon.ConnectionEvents + 67, // 83: daemon.StartedService.CloseConnection:output_type -> google.protobuf.Empty + 67, // 84: daemon.StartedService.CloseAllConnections:output_type -> google.protobuf.Empty + 25, // 85: daemon.StartedService.GetDeprecatedWarnings:output_type -> daemon.DeprecatedWarnings + 27, // 86: daemon.StartedService.GetStartedAt:output_type -> daemon.StartedAt + 28, // 87: daemon.StartedService.SubscribeOutbounds:output_type -> daemon.OutboundList + 30, // 88: daemon.StartedService.StartNetworkQualityTest:output_type -> daemon.NetworkQualityTestProgress + 32, // 89: daemon.StartedService.StartSTUNTest:output_type -> daemon.STUNTestProgress + 33, // 90: daemon.StartedService.SubscribeTailscaleStatus:output_type -> daemon.TailscaleStatusUpdate + 38, // 91: daemon.StartedService.StartTailscalePing:output_type -> daemon.TailscalePingResponse + 67, // 92: daemon.StartedService.SetTailscaleExitNode:output_type -> google.protobuf.Empty + 67, // 93: daemon.StartedService.TailscaleLogout:output_type -> google.protobuf.Empty + 45, // 94: daemon.StartedService.StartTailscaleSSHSession:output_type -> daemon.TailscaleSSHServerMessage + 52, // 95: daemon.StartedService.ProvideUSBDevices:output_type -> daemon.USBServerMessage + 63, // 96: daemon.StartedService.SubscribeUSBIPServerStatus:output_type -> daemon.USBIPServerStatusUpdate + 69, // [69:97] is the sub-list for method output_type + 41, // [41:69] is the sub-list for method input_type + 41, // [41:41] is the sub-list for extension type_name + 41, // [41:41] is the sub-list for extension extendee + 0, // [0:41] is the sub-list for field type_name } func init() { file_daemon_started_service_proto_init() } @@ -3910,13 +5294,24 @@ func file_daemon_started_service_proto_init() { (*TailscaleSSHServerMessage_Exit)(nil), (*TailscaleSSHServerMessage_Error)(nil), } + file_daemon_started_service_proto_msgTypes[46].OneofWrappers = []any{ + (*USBProviderMessage_Attach)(nil), + (*USBProviderMessage_Detach)(nil), + (*USBProviderMessage_UrbResponse)(nil), + } + file_daemon_started_service_proto_msgTypes[47].OneofWrappers = []any{ + (*USBServerMessage_Ready)(nil), + (*USBServerMessage_UrbRequest)(nil), + (*USBServerMessage_Abort)(nil), + (*USBServerMessage_Error)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_daemon_started_service_proto_rawDesc), len(file_daemon_started_service_proto_rawDesc)), - NumEnums: 3, - NumMessages: 47, + NumEnums: 5, + NumMessages: 62, NumExtensions: 0, NumServices: 1, }, diff --git a/daemon/started_service.proto b/daemon/started_service.proto index f03deef71..97af9f8c4 100644 --- a/daemon/started_service.proto +++ b/daemon/started_service.proto @@ -22,8 +22,6 @@ service StartedService { rpc SelectOutbound(SelectOutboundRequest) returns (google.protobuf.Empty) {} rpc SetGroupExpand(SetGroupExpandRequest) returns (google.protobuf.Empty) {} - rpc TriggerOOMReport(google.protobuf.Empty) returns(google.protobuf.Empty) {} - rpc SubscribeConnections(SubscribeConnectionsRequest) returns(stream ConnectionEvents) {} rpc CloseConnection(CloseConnectionRequest) returns(google.protobuf.Empty) {} rpc CloseAllConnections(google.protobuf.Empty) returns(google.protobuf.Empty) {} @@ -38,6 +36,8 @@ service StartedService { rpc SetTailscaleExitNode(SetTailscaleExitNodeRequest) returns (google.protobuf.Empty) {} rpc TailscaleLogout(TailscaleLogoutRequest) returns (google.protobuf.Empty) {} rpc StartTailscaleSSHSession(stream TailscaleSSHClientMessage) returns (stream TailscaleSSHServerMessage) {} + rpc ProvideUSBDevices(stream USBProviderMessage) returns (stream USBServerMessage) {} + rpc SubscribeUSBIPServerStatus(google.protobuf.Empty) returns (stream USBIPServerStatusUpdate) {} } message Version { @@ -389,3 +389,130 @@ message TailscaleSSHExit { message TailscaleSSHError { string message = 1; } + +message USBProviderMessage { + oneof message { + USBDeviceAttach attach = 1; + USBDeviceDetach detach = 2; + USBURBResponse urbResponse = 3; + } +} + +message USBServerMessage { + oneof message { + USBDeviceReady ready = 1; + USBURBRequest urbRequest = 2; + USBEndpointAbort abort = 3; + USBError error = 4; + } +} + +message USBDeviceDescriptor { + string deviceId = 1; + uint32 busNum = 2; + uint32 devNum = 3; + uint32 speed = 4; + uint32 vendorId = 5; + uint32 productId = 6; + uint32 bcdDevice = 7; + uint32 deviceClass = 8; + uint32 deviceSubClass = 9; + uint32 deviceProtocol = 10; + uint32 configurationValue = 11; + uint32 numConfigurations = 12; + repeated USBInterface interfaces = 13; + string serial = 14; + string product = 15; +} + +message USBDeviceAttach { + string serverTag = 1; + USBDeviceDescriptor descriptor = 2; +} + +message USBInterface { + uint32 interfaceClass = 1; + uint32 interfaceSubClass = 2; + uint32 interfaceProtocol = 3; +} + +message USBDeviceDetach { + string deviceId = 1; +} + +message USBDeviceReady { + string deviceId = 1; + string busId = 2; +} + +message USBURBRequest { + string deviceId = 1; + uint64 seq = 2; + uint32 endpoint = 3; + bool directionIn = 4; + uint32 transferFlags = 5; + bytes setup = 6; + uint32 transferBufferLength = 7; + bytes outData = 8; + int32 numberOfPackets = 9; + int32 startFrame = 10; + int32 interval = 11; + repeated USBIsoPacket isoPackets = 12; +} + +message USBURBResponse { + string deviceId = 1; + uint64 seq = 2; + int32 status = 3; + int32 actualLength = 4; + bytes inData = 5; + repeated USBIsoPacket isoPackets = 6; +} + +message USBIsoPacket { + int32 offset = 1; + int32 length = 2; + int32 actualLength = 3; + int32 status = 4; +} + +message USBEndpointAbort { + string deviceId = 1; + uint32 endpoint = 2; +} + +message USBError { + string deviceId = 1; + string message = 2; +} + +message USBIPServerStatusUpdate { + repeated USBIPServerStatus servers = 1; +} + +message USBIPServerStatus { + string serverTag = 1; + repeated USBSharedDevice devices = 2; +} + +message USBSharedDevice { + USBDeviceDescriptor descriptor = 1; + string busId = 2; + string stableId = 3; + USBBackend backend = 4; + USBDeviceState state = 5; +} + +enum USBDeviceState { + USB_DEVICE_STATE_IDLE = 0; + USB_DEVICE_STATE_ATTACHED = 1; + USB_DEVICE_STATE_UNAVAILABLE = 2; +} + +enum USBBackend { + USB_BACKEND_UNSPECIFIED = 0; + USB_BACKEND_LINUX_SYSFS = 1; + USB_BACKEND_DYNAMIC = 2; + USB_BACKEND_DARWIN_IOKIT = 3; + USB_BACKEND_WINDOWS_VBOXUSB = 4; +} diff --git a/daemon/started_service_grpc.pb.go b/daemon/started_service_grpc.pb.go index 398edaee3..a707fdb38 100644 --- a/daemon/started_service_grpc.pb.go +++ b/daemon/started_service_grpc.pb.go @@ -15,33 +15,34 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( - StartedService_GetVersion_FullMethodName = "/daemon.StartedService/GetVersion" - StartedService_SubscribeServiceStatus_FullMethodName = "/daemon.StartedService/SubscribeServiceStatus" - StartedService_SubscribeLog_FullMethodName = "/daemon.StartedService/SubscribeLog" - StartedService_GetDefaultLogLevel_FullMethodName = "/daemon.StartedService/GetDefaultLogLevel" - StartedService_ClearLogs_FullMethodName = "/daemon.StartedService/ClearLogs" - StartedService_SubscribeStatus_FullMethodName = "/daemon.StartedService/SubscribeStatus" - StartedService_SubscribeGroups_FullMethodName = "/daemon.StartedService/SubscribeGroups" - StartedService_GetClashModeStatus_FullMethodName = "/daemon.StartedService/GetClashModeStatus" - StartedService_SubscribeClashMode_FullMethodName = "/daemon.StartedService/SubscribeClashMode" - StartedService_SetClashMode_FullMethodName = "/daemon.StartedService/SetClashMode" - StartedService_URLTest_FullMethodName = "/daemon.StartedService/URLTest" - StartedService_SelectOutbound_FullMethodName = "/daemon.StartedService/SelectOutbound" - StartedService_SetGroupExpand_FullMethodName = "/daemon.StartedService/SetGroupExpand" - StartedService_TriggerOOMReport_FullMethodName = "/daemon.StartedService/TriggerOOMReport" - StartedService_SubscribeConnections_FullMethodName = "/daemon.StartedService/SubscribeConnections" - StartedService_CloseConnection_FullMethodName = "/daemon.StartedService/CloseConnection" - StartedService_CloseAllConnections_FullMethodName = "/daemon.StartedService/CloseAllConnections" - StartedService_GetDeprecatedWarnings_FullMethodName = "/daemon.StartedService/GetDeprecatedWarnings" - StartedService_GetStartedAt_FullMethodName = "/daemon.StartedService/GetStartedAt" - StartedService_SubscribeOutbounds_FullMethodName = "/daemon.StartedService/SubscribeOutbounds" - StartedService_StartNetworkQualityTest_FullMethodName = "/daemon.StartedService/StartNetworkQualityTest" - StartedService_StartSTUNTest_FullMethodName = "/daemon.StartedService/StartSTUNTest" - StartedService_SubscribeTailscaleStatus_FullMethodName = "/daemon.StartedService/SubscribeTailscaleStatus" - StartedService_StartTailscalePing_FullMethodName = "/daemon.StartedService/StartTailscalePing" - StartedService_SetTailscaleExitNode_FullMethodName = "/daemon.StartedService/SetTailscaleExitNode" - StartedService_TailscaleLogout_FullMethodName = "/daemon.StartedService/TailscaleLogout" - StartedService_StartTailscaleSSHSession_FullMethodName = "/daemon.StartedService/StartTailscaleSSHSession" + StartedService_GetVersion_FullMethodName = "/daemon.StartedService/GetVersion" + StartedService_SubscribeServiceStatus_FullMethodName = "/daemon.StartedService/SubscribeServiceStatus" + StartedService_SubscribeLog_FullMethodName = "/daemon.StartedService/SubscribeLog" + StartedService_GetDefaultLogLevel_FullMethodName = "/daemon.StartedService/GetDefaultLogLevel" + StartedService_ClearLogs_FullMethodName = "/daemon.StartedService/ClearLogs" + StartedService_SubscribeStatus_FullMethodName = "/daemon.StartedService/SubscribeStatus" + StartedService_SubscribeGroups_FullMethodName = "/daemon.StartedService/SubscribeGroups" + StartedService_GetClashModeStatus_FullMethodName = "/daemon.StartedService/GetClashModeStatus" + StartedService_SubscribeClashMode_FullMethodName = "/daemon.StartedService/SubscribeClashMode" + StartedService_SetClashMode_FullMethodName = "/daemon.StartedService/SetClashMode" + StartedService_URLTest_FullMethodName = "/daemon.StartedService/URLTest" + StartedService_SelectOutbound_FullMethodName = "/daemon.StartedService/SelectOutbound" + StartedService_SetGroupExpand_FullMethodName = "/daemon.StartedService/SetGroupExpand" + StartedService_SubscribeConnections_FullMethodName = "/daemon.StartedService/SubscribeConnections" + StartedService_CloseConnection_FullMethodName = "/daemon.StartedService/CloseConnection" + StartedService_CloseAllConnections_FullMethodName = "/daemon.StartedService/CloseAllConnections" + StartedService_GetDeprecatedWarnings_FullMethodName = "/daemon.StartedService/GetDeprecatedWarnings" + StartedService_GetStartedAt_FullMethodName = "/daemon.StartedService/GetStartedAt" + StartedService_SubscribeOutbounds_FullMethodName = "/daemon.StartedService/SubscribeOutbounds" + StartedService_StartNetworkQualityTest_FullMethodName = "/daemon.StartedService/StartNetworkQualityTest" + StartedService_StartSTUNTest_FullMethodName = "/daemon.StartedService/StartSTUNTest" + StartedService_SubscribeTailscaleStatus_FullMethodName = "/daemon.StartedService/SubscribeTailscaleStatus" + StartedService_StartTailscalePing_FullMethodName = "/daemon.StartedService/StartTailscalePing" + StartedService_SetTailscaleExitNode_FullMethodName = "/daemon.StartedService/SetTailscaleExitNode" + StartedService_TailscaleLogout_FullMethodName = "/daemon.StartedService/TailscaleLogout" + StartedService_StartTailscaleSSHSession_FullMethodName = "/daemon.StartedService/StartTailscaleSSHSession" + StartedService_ProvideUSBDevices_FullMethodName = "/daemon.StartedService/ProvideUSBDevices" + StartedService_SubscribeUSBIPServerStatus_FullMethodName = "/daemon.StartedService/SubscribeUSBIPServerStatus" ) // StartedServiceClient is the client API for StartedService service. @@ -61,7 +62,6 @@ type StartedServiceClient interface { URLTest(ctx context.Context, in *URLTestRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) SelectOutbound(ctx context.Context, in *SelectOutboundRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) SetGroupExpand(ctx context.Context, in *SetGroupExpandRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) - TriggerOOMReport(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) SubscribeConnections(ctx context.Context, in *SubscribeConnectionsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ConnectionEvents], error) CloseConnection(ctx context.Context, in *CloseConnectionRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) CloseAllConnections(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) @@ -75,6 +75,8 @@ type StartedServiceClient interface { SetTailscaleExitNode(ctx context.Context, in *SetTailscaleExitNodeRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) TailscaleLogout(ctx context.Context, in *TailscaleLogoutRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) StartTailscaleSSHSession(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[TailscaleSSHClientMessage, TailscaleSSHServerMessage], error) + ProvideUSBDevices(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[USBProviderMessage, USBServerMessage], error) + SubscribeUSBIPServerStatus(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (grpc.ServerStreamingClient[USBIPServerStatusUpdate], error) } type startedServiceClient struct { @@ -260,16 +262,6 @@ func (c *startedServiceClient) SetGroupExpand(ctx context.Context, in *SetGroupE return out, nil } -func (c *startedServiceClient) TriggerOOMReport(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, StartedService_TriggerOOMReport_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *startedServiceClient) SubscribeConnections(ctx context.Context, in *SubscribeConnectionsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ConnectionEvents], error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) stream, err := c.cc.NewStream(ctx, &StartedService_ServiceDesc.Streams[5], StartedService_SubscribeConnections_FullMethodName, cOpts...) @@ -457,6 +449,38 @@ func (c *startedServiceClient) StartTailscaleSSHSession(ctx context.Context, opt // This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. type StartedService_StartTailscaleSSHSessionClient = grpc.BidiStreamingClient[TailscaleSSHClientMessage, TailscaleSSHServerMessage] +func (c *startedServiceClient) ProvideUSBDevices(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[USBProviderMessage, USBServerMessage], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &StartedService_ServiceDesc.Streams[12], StartedService_ProvideUSBDevices_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[USBProviderMessage, USBServerMessage]{ClientStream: stream} + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type StartedService_ProvideUSBDevicesClient = grpc.BidiStreamingClient[USBProviderMessage, USBServerMessage] + +func (c *startedServiceClient) SubscribeUSBIPServerStatus(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (grpc.ServerStreamingClient[USBIPServerStatusUpdate], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &StartedService_ServiceDesc.Streams[13], StartedService_SubscribeUSBIPServerStatus_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[emptypb.Empty, USBIPServerStatusUpdate]{ClientStream: stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type StartedService_SubscribeUSBIPServerStatusClient = grpc.ServerStreamingClient[USBIPServerStatusUpdate] + // StartedServiceServer is the server API for StartedService service. // All implementations must embed UnimplementedStartedServiceServer // for forward compatibility. @@ -474,7 +498,6 @@ type StartedServiceServer interface { URLTest(context.Context, *URLTestRequest) (*emptypb.Empty, error) SelectOutbound(context.Context, *SelectOutboundRequest) (*emptypb.Empty, error) SetGroupExpand(context.Context, *SetGroupExpandRequest) (*emptypb.Empty, error) - TriggerOOMReport(context.Context, *emptypb.Empty) (*emptypb.Empty, error) SubscribeConnections(*SubscribeConnectionsRequest, grpc.ServerStreamingServer[ConnectionEvents]) error CloseConnection(context.Context, *CloseConnectionRequest) (*emptypb.Empty, error) CloseAllConnections(context.Context, *emptypb.Empty) (*emptypb.Empty, error) @@ -488,6 +511,8 @@ type StartedServiceServer interface { SetTailscaleExitNode(context.Context, *SetTailscaleExitNodeRequest) (*emptypb.Empty, error) TailscaleLogout(context.Context, *TailscaleLogoutRequest) (*emptypb.Empty, error) StartTailscaleSSHSession(grpc.BidiStreamingServer[TailscaleSSHClientMessage, TailscaleSSHServerMessage]) error + ProvideUSBDevices(grpc.BidiStreamingServer[USBProviderMessage, USBServerMessage]) error + SubscribeUSBIPServerStatus(*emptypb.Empty, grpc.ServerStreamingServer[USBIPServerStatusUpdate]) error mustEmbedUnimplementedStartedServiceServer() } @@ -550,10 +575,6 @@ func (UnimplementedStartedServiceServer) SetGroupExpand(context.Context, *SetGro return nil, status.Error(codes.Unimplemented, "method SetGroupExpand not implemented") } -func (UnimplementedStartedServiceServer) TriggerOOMReport(context.Context, *emptypb.Empty) (*emptypb.Empty, error) { - return nil, status.Error(codes.Unimplemented, "method TriggerOOMReport not implemented") -} - func (UnimplementedStartedServiceServer) SubscribeConnections(*SubscribeConnectionsRequest, grpc.ServerStreamingServer[ConnectionEvents]) error { return status.Error(codes.Unimplemented, "method SubscribeConnections not implemented") } @@ -605,6 +626,14 @@ func (UnimplementedStartedServiceServer) TailscaleLogout(context.Context, *Tails func (UnimplementedStartedServiceServer) StartTailscaleSSHSession(grpc.BidiStreamingServer[TailscaleSSHClientMessage, TailscaleSSHServerMessage]) error { return status.Error(codes.Unimplemented, "method StartTailscaleSSHSession not implemented") } + +func (UnimplementedStartedServiceServer) ProvideUSBDevices(grpc.BidiStreamingServer[USBProviderMessage, USBServerMessage]) error { + return status.Error(codes.Unimplemented, "method ProvideUSBDevices not implemented") +} + +func (UnimplementedStartedServiceServer) SubscribeUSBIPServerStatus(*emptypb.Empty, grpc.ServerStreamingServer[USBIPServerStatusUpdate]) error { + return status.Error(codes.Unimplemented, "method SubscribeUSBIPServerStatus not implemented") +} func (UnimplementedStartedServiceServer) mustEmbedUnimplementedStartedServiceServer() {} func (UnimplementedStartedServiceServer) testEmbeddedByValue() {} @@ -825,24 +854,6 @@ func _StartedService_SetGroupExpand_Handler(srv interface{}, ctx context.Context return interceptor(ctx, in, info, handler) } -func _StartedService_TriggerOOMReport_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(emptypb.Empty) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(StartedServiceServer).TriggerOOMReport(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: StartedService_TriggerOOMReport_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(StartedServiceServer).TriggerOOMReport(ctx, req.(*emptypb.Empty)) - } - return interceptor(ctx, in, info, handler) -} - func _StartedService_SubscribeConnections_Handler(srv interface{}, stream grpc.ServerStream) error { m := new(SubscribeConnectionsRequest) if err := stream.RecvMsg(m); err != nil { @@ -1024,6 +1035,24 @@ func _StartedService_StartTailscaleSSHSession_Handler(srv interface{}, stream gr // This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. type StartedService_StartTailscaleSSHSessionServer = grpc.BidiStreamingServer[TailscaleSSHClientMessage, TailscaleSSHServerMessage] +func _StartedService_ProvideUSBDevices_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(StartedServiceServer).ProvideUSBDevices(&grpc.GenericServerStream[USBProviderMessage, USBServerMessage]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type StartedService_ProvideUSBDevicesServer = grpc.BidiStreamingServer[USBProviderMessage, USBServerMessage] + +func _StartedService_SubscribeUSBIPServerStatus_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(emptypb.Empty) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(StartedServiceServer).SubscribeUSBIPServerStatus(m, &grpc.GenericServerStream[emptypb.Empty, USBIPServerStatusUpdate]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type StartedService_SubscribeUSBIPServerStatusServer = grpc.ServerStreamingServer[USBIPServerStatusUpdate] + // StartedService_ServiceDesc is the grpc.ServiceDesc for StartedService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -1063,10 +1092,6 @@ var StartedService_ServiceDesc = grpc.ServiceDesc{ MethodName: "SetGroupExpand", Handler: _StartedService_SetGroupExpand_Handler, }, - { - MethodName: "TriggerOOMReport", - Handler: _StartedService_TriggerOOMReport_Handler, - }, { MethodName: "CloseConnection", Handler: _StartedService_CloseConnection_Handler, @@ -1154,6 +1179,17 @@ var StartedService_ServiceDesc = grpc.ServiceDesc{ ServerStreams: true, ClientStreams: true, }, + { + StreamName: "ProvideUSBDevices", + Handler: _StartedService_ProvideUSBDevices_Handler, + ServerStreams: true, + ClientStreams: true, + }, + { + StreamName: "SubscribeUSBIPServerStatus", + Handler: _StartedService_SubscribeUSBIPServerStatus_Handler, + ServerStreams: true, + }, }, Metadata: "daemon/started_service.proto", } diff --git a/daemon/started_service_usbip.go b/daemon/started_service_usbip.go new file mode 100644 index 000000000..093bcfd08 --- /dev/null +++ b/daemon/started_service_usbip.go @@ -0,0 +1,459 @@ +//go:build with_usbip && (linux || (darwin && cgo) || windows) + +package daemon + +import ( + "context" + "io" + "sync" + "sync/atomic" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-usbip" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/service" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/emptypb" +) + +func (s *StartedService) ProvideUSBDevices(server grpc.BidiStreamingServer[USBProviderMessage, USBServerMessage]) error { + ctx := server.Context() + err := s.waitForStarted(ctx) + if err != nil { + return err + } + s.serviceAccess.RLock() + instance := s.instance + s.serviceAccess.RUnlock() + if instance == nil { + return E.New("service not started") + } + serviceManager := service.FromContext[adapter.ServiceManager](instance.ctx) + if serviceManager == nil { + return E.New("missing service manager") + } + + sessionCtx, cancel := context.WithCancel(ctx) + defer cancel() + + var sendAccess sync.Mutex + send := func(message *USBServerMessage) error { + sendAccess.Lock() + defer sendAccess.Unlock() + return server.Send(message) + } + + var devicesAccess sync.Mutex + devices := make(map[string]*usbProvidedDevice) + defer func() { + devicesAccess.Lock() + for _, device := range devices { + device.close() + } + devicesAccess.Unlock() + }() + + for { + message, recvErr := server.Recv() + if recvErr != nil { + if recvErr == io.EOF { + return nil + } + return recvErr + } + switch body := message.GetMessage().(type) { + case *USBProviderMessage_Attach: + attach := body.Attach + deviceID := attach.GetDescriptor_().GetDeviceId() + device, addErr := addUSBDevice(sessionCtx, serviceManager, send, attach) + if addErr != nil { + _ = send(&USBServerMessage{Message: &USBServerMessage_Error{Error: &USBError{ + DeviceId: deviceID, + Message: addErr.Error(), + }}}) + continue + } + devicesAccess.Lock() + previous, replaced := devices[deviceID] + devices[deviceID] = device + devicesAccess.Unlock() + if replaced { + previous.close() + } + _ = send(&USBServerMessage{Message: &USBServerMessage_Ready{Ready: &USBDeviceReady{ + DeviceId: deviceID, + BusId: device.busID, + }}}) + case *USBProviderMessage_Detach: + deviceID := body.Detach.GetDeviceId() + devicesAccess.Lock() + device, found := devices[deviceID] + if found { + delete(devices, deviceID) + } + devicesAccess.Unlock() + if found { + device.close() + } + case *USBProviderMessage_UrbResponse: + response := body.UrbResponse + devicesAccess.Lock() + device, found := devices[response.GetDeviceId()] + devicesAccess.Unlock() + if found { + device.deliver(response) + } + } + } +} + +func (s *StartedService) SubscribeUSBIPServerStatus( + _ *emptypb.Empty, + server grpc.ServerStreamingServer[USBIPServerStatusUpdate], +) error { + err := s.waitForStarted(server.Context()) + if err != nil { + return err + } + s.serviceAccess.RLock() + instance := s.instance + s.serviceAccess.RUnlock() + if instance == nil { + return E.New("service not started") + } + serviceManager := service.FromContext[adapter.ServiceManager](instance.ctx) + if serviceManager == nil { + return status.Error(codes.FailedPrecondition, "service manager not available") + } + + type usbipServer struct { + tag string + provider adapter.USBIPDynamicServer + } + var servers []usbipServer + for _, serverService := range serviceManager.Services() { + provider, isDynamic := serverService.(adapter.USBIPDynamicServer) + if !isDynamic { + continue + } + servers = append(servers, usbipServer{tag: serverService.Tag(), provider: provider}) + } + if len(servers) == 0 { + return status.Error(codes.NotFound, "no usbip-server found") + } + + type taggedStatus struct { + tag string + devices []usbip.ControlDeviceInfo + } + updates := make(chan taggedStatus, len(servers)) + ctx, cancel := context.WithCancel(server.Context()) + defer cancel() + + var waitGroup sync.WaitGroup + for _, srv := range servers { + // sing-usbip invokes the SubscribeDevices listener while holding the + // ledger's broadcast lock, so it must never block. + latest := make(chan []usbip.ControlDeviceInfo, 1) + waitGroup.Add(1) + go func(provider adapter.USBIPDynamicServer) { + defer waitGroup.Done() + provider.SubscribeDevices(ctx, func(devices []usbip.ControlDeviceInfo) { + sendLatestUSBSnapshot(latest, devices) + }) + }(srv.provider) + waitGroup.Add(1) + go func(tag string) { + defer waitGroup.Done() + for { + select { + case <-ctx.Done(): + return + case devices := <-latest: + select { + case updates <- taggedStatus{tag: tag, devices: devices}: + case <-ctx.Done(): + return + } + } + } + }(srv.tag) + } + + go func() { + waitGroup.Wait() + close(updates) + }() + + var tags []string + deviceStates := make(map[string][]usbip.ControlDeviceInfo, len(servers)) + for update := range updates { + if _, exists := deviceStates[update.tag]; !exists { + tags = append(tags, update.tag) + } + deviceStates[update.tag] = update.devices + protoServers := make([]*USBIPServerStatus, 0, len(deviceStates)) + for _, tag := range tags { + protoServers = append(protoServers, &USBIPServerStatus{ + ServerTag: tag, + Devices: usbSharedDevicesToProto(deviceStates[tag]), + }) + } + sendErr := server.Send(&USBIPServerStatusUpdate{Servers: protoServers}) + if sendErr != nil { + return sendErr + } + } + return nil +} + +func sendLatestUSBSnapshot(slot chan []usbip.ControlDeviceInfo, devices []usbip.ControlDeviceInfo) { + select { + case slot <- devices: + return + default: + } + select { + case <-slot: + default: + } + select { + case slot <- devices: + default: + } +} + +func usbSharedDevicesToProto(devices []usbip.ControlDeviceInfo) []*USBSharedDevice { + if len(devices) == 0 { + return nil + } + out := make([]*USBSharedDevice, 0, len(devices)) + for _, device := range devices { + interfaces := make([]*USBInterface, 0, len(device.Interfaces)) + for _, deviceInterface := range device.Interfaces { + interfaces = append(interfaces, &USBInterface{ + InterfaceClass: uint32(deviceInterface.Class), + InterfaceSubClass: uint32(deviceInterface.SubClass), + InterfaceProtocol: uint32(deviceInterface.Protocol), + }) + } + out = append(out, &USBSharedDevice{ + Descriptor_: &USBDeviceDescriptor{ + DeviceId: device.BusID, + BusNum: device.BusNum, + DevNum: device.DevNum, + Speed: device.Speed, + VendorId: uint32(device.VendorID), + ProductId: uint32(device.ProductID), + BcdDevice: uint32(device.BCDDevice), + DeviceClass: uint32(device.DeviceClass), + DeviceSubClass: uint32(device.DeviceSubClass), + DeviceProtocol: uint32(device.DeviceProtocol), + ConfigurationValue: uint32(device.ConfigurationValue), + NumConfigurations: uint32(device.NumConfigurations), + Interfaces: interfaces, + Serial: device.Serial, + Product: device.Product, + }, + BusId: device.BusID, + StableId: device.StableID, + Backend: USBBackend(device.Backend), + State: USBDeviceState(device.State), + }) + } + return out +} + +func addUSBDevice(ctx context.Context, serviceManager adapter.ServiceManager, send func(*USBServerMessage) error, attach *USBDeviceAttach) (*usbProvidedDevice, error) { + serverService, found := serviceManager.Get(attach.GetServerTag()) + if !found { + return nil, E.New("usbip-server not found: ", attach.GetServerTag()) + } + provider, isDynamic := serverService.(adapter.USBIPDynamicServer) + if !isDynamic { + return nil, E.New("service ", attach.GetServerTag(), " is not a dynamic usbip-server") + } + descriptor := attach.GetDescriptor_() + if descriptor == nil { + return nil, E.New("missing device descriptor") + } + device := &usbProvidedDevice{ + deviceID: descriptor.GetDeviceId(), + provider: provider, + send: send, + ctx: ctx, + pending: make(map[uint64]chan *USBURBResponse), + } + busID, err := provider.AddDevice(usbip.DynamicDeviceInfo{ + BusID: descriptor.GetDeviceId(), + BusNum: descriptor.GetBusNum(), + DevNum: descriptor.GetDevNum(), + Speed: descriptor.GetSpeed(), + VendorID: uint16(descriptor.GetVendorId()), + ProductID: uint16(descriptor.GetProductId()), + BCDDevice: uint16(descriptor.GetBcdDevice()), + DeviceClass: uint8(descriptor.GetDeviceClass()), + DeviceSubClass: uint8(descriptor.GetDeviceSubClass()), + DeviceProtocol: uint8(descriptor.GetDeviceProtocol()), + ConfigurationValue: uint8(descriptor.GetConfigurationValue()), + NumConfigurations: uint8(descriptor.GetNumConfigurations()), + Interfaces: usbInterfacesFromProto(descriptor.GetInterfaces()), + Serial: descriptor.GetSerial(), + Product: descriptor.GetProduct(), + }, device) + if err != nil { + return nil, err + } + device.busID = busID + return device, nil +} + +// sing-usbip calls Submit concurrently across endpoints for a single device. +type usbProvidedDevice struct { + deviceID string + busID string + provider adapter.USBIPDynamicServer + send func(*USBServerMessage) error + ctx context.Context + + seq atomic.Uint64 + access sync.Mutex + pending map[uint64]chan *USBURBResponse + closed bool +} + +func (d *usbProvidedDevice) Submit(request usbip.URBRequest) usbip.URBResponse { + seq := d.seq.Add(1) + responseChan := make(chan *USBURBResponse, 1) + d.access.Lock() + if d.closed { + d.access.Unlock() + return usbip.URBResponse{Error: E.New("device detached")} + } + d.pending[seq] = responseChan + d.access.Unlock() + defer func() { + d.access.Lock() + delete(d.pending, seq) + d.access.Unlock() + }() + + directionIn := request.Endpoint&0x80 != 0 + message := &USBURBRequest{ + DeviceId: d.deviceID, + Seq: seq, + Endpoint: uint32(request.Endpoint), + DirectionIn: directionIn, + TransferFlags: uint32(request.Command.TransferFlags), + Setup: append([]byte(nil), request.Command.Setup[:]...), + TransferBufferLength: uint32(request.Command.TransferBufferLength), + NumberOfPackets: request.Command.NumberOfPackets, + StartFrame: request.Command.StartFrame, + Interval: request.Command.Interval, + IsoPackets: isoPacketsToProto(request.IsoPackets), + } + if !directionIn { + message.OutData = request.Buffer + } + sendErr := d.send(&USBServerMessage{Message: &USBServerMessage_UrbRequest{UrbRequest: message}}) + if sendErr != nil { + return usbip.URBResponse{Error: sendErr} + } + select { + case <-d.ctx.Done(): + return usbip.URBResponse{Error: d.ctx.Err()} + case response := <-responseChan: + result := usbip.URBResponse{ + Status: response.GetStatus(), + ActualLength: response.GetActualLength(), + IsoPackets: isoPacketsFromProto(response.GetIsoPackets()), + } + if directionIn { + result.Buffer = response.GetInData() + } + return result + } +} + +func (d *usbProvidedDevice) AbortEndpoint(endpoint uint8) error { + return d.send(&USBServerMessage{Message: &USBServerMessage_Abort{Abort: &USBEndpointAbort{ + DeviceId: d.deviceID, + Endpoint: uint32(endpoint), + }}}) +} + +func (d *usbProvidedDevice) deliver(response *USBURBResponse) { + d.access.Lock() + responseChan, found := d.pending[response.GetSeq()] + d.access.Unlock() + if !found { + return + } + select { + case responseChan <- response: + default: + } +} + +func (d *usbProvidedDevice) close() { + d.access.Lock() + if d.closed { + d.access.Unlock() + return + } + d.closed = true + d.access.Unlock() + if d.busID != "" { + d.provider.RemoveDevice(d.busID) + } +} + +func usbInterfacesFromProto(interfaces []*USBInterface) []usbip.DeviceInterface { + if len(interfaces) == 0 { + return nil + } + deviceInterfaces := make([]usbip.DeviceInterface, 0, len(interfaces)) + for _, deviceInterface := range interfaces { + deviceInterfaces = append(deviceInterfaces, usbip.DeviceInterface{ + BInterfaceClass: uint8(deviceInterface.GetInterfaceClass()), + BInterfaceSubClass: uint8(deviceInterface.GetInterfaceSubClass()), + BInterfaceProtocol: uint8(deviceInterface.GetInterfaceProtocol()), + }) + } + return deviceInterfaces +} + +func isoPacketsToProto(packets []usbip.IsoPacketDescriptor) []*USBIsoPacket { + if len(packets) == 0 { + return nil + } + out := make([]*USBIsoPacket, 0, len(packets)) + for _, packet := range packets { + out = append(out, &USBIsoPacket{ + Offset: packet.Offset, + Length: packet.Length, + ActualLength: packet.ActualLength, + Status: packet.Status, + }) + } + return out +} + +func isoPacketsFromProto(packets []*USBIsoPacket) []usbip.IsoPacketDescriptor { + if len(packets) == 0 { + return nil + } + out := make([]usbip.IsoPacketDescriptor, 0, len(packets)) + for _, packet := range packets { + out = append(out, usbip.IsoPacketDescriptor{ + Offset: packet.GetOffset(), + Length: packet.GetLength(), + ActualLength: packet.GetActualLength(), + Status: packet.GetStatus(), + }) + } + return out +} diff --git a/daemon/started_service_usbip_stub.go b/daemon/started_service_usbip_stub.go new file mode 100644 index 000000000..e4d787fe9 --- /dev/null +++ b/daemon/started_service_usbip_stub.go @@ -0,0 +1,18 @@ +//go:build !with_usbip || !(linux || (darwin && cgo) || windows) + +package daemon + +import ( + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/emptypb" +) + +func (s *StartedService) ProvideUSBDevices(server grpc.BidiStreamingServer[USBProviderMessage, USBServerMessage]) error { + return status.Error(codes.Unimplemented, "USB/IP is not included in this build, rebuild with -tags with_usbip") +} + +func (s *StartedService) SubscribeUSBIPServerStatus(_ *emptypb.Empty, server grpc.ServerStreamingServer[USBIPServerStatusUpdate]) error { + return status.Error(codes.NotFound, "USB/IP is not included in this build, rebuild with -tags with_usbip") +} diff --git a/experimental/libbox/command_client.go b/experimental/libbox/command_client.go index 5d2c25507..1ab368785 100644 --- a/experimental/libbox/command_client.go +++ b/experimental/libbox/command_client.go @@ -673,7 +673,7 @@ func (c *CommandClient) TriggerNativeCrash() error { } func (c *CommandClient) TriggerOOMReport() error { - _, err := callWithResult(c, func(ctx context.Context, client daemon.StartedServiceClient) (*emptypb.Empty, error) { + _, err := callManagedWithResult(c, func(ctx context.Context, client daemon.ManagedServiceClient) (*emptypb.Empty, error) { return client.TriggerOOMReport(ctx, &emptypb.Empty{}) }) if err != nil { @@ -924,6 +924,61 @@ func (c *CommandClient) SubscribeTailscaleStatus(handler TailscaleStatusHandler) return session, nil } +func (c *CommandClient) SubscribeUSBIPServerStatus(handler USBIPServerStatusHandler) (*USBIPServerStatusSubscription, error) { + client, parentCtx, err := c.getClientForCall() + if err != nil { + return nil, E.Cause(err, "subscribe usbip server status") + } + + streamCtx, cancel := context.WithCancel(parentCtx) + session := &USBIPServerStatusSubscription{ + streamSession: streamSession{ + ctx: streamCtx, + cancel: cancel, + closeDone: make(chan struct{}), + }, + } + + failStart := func(cause error, message string) (*USBIPServerStatusSubscription, error) { + cancel() + if c.standalone { + c.closeConnection() + } + return nil, E.Cause(cause, message) + } + + stream, err := client.SubscribeUSBIPServerStatus(streamCtx, &emptypb.Empty{}) + if err != nil { + return failStart(err, "subscribe usbip server status") + } + + standalone := c.standalone + go func() { + defer func() { + close(session.closeDone) + if standalone { + c.closeConnection() + } + }() + for { + event, recvErr := stream.Recv() + if recvErr != nil { + if session.ctx.Err() != nil { + return + } + if status.Code(recvErr) == codes.NotFound || status.Code(recvErr) == codes.Unavailable { + return + } + handler.OnError(E.Cause(recvErr, "usbip server status recv").Error()) + return + } + handler.OnStatusUpdate(usbipServerStatusUpdateFromGRPC(event)) + } + }() + + return session, nil +} + func (c *CommandClient) SetTailscaleExitNode(endpointTag string, stableID string) error { _, err := callWithResult(c, func(ctx context.Context, client daemon.StartedServiceClient) (*emptypb.Empty, error) { return client.SetTailscaleExitNode(ctx, &daemon.SetTailscaleExitNodeRequest{ @@ -1125,3 +1180,59 @@ func (c *CommandClient) StartTailscaleSSHSession(opts *TailscaleSSHOptions, hand return session, nil } + +func (c *CommandClient) ProvideUSBDevices(handler USBProviderHandler) (*USBProviderSession, error) { + client, parentCtx, err := c.getClientForCall() + if err != nil { + return nil, E.Cause(err, "provide usb devices") + } + + streamCtx, cancel := context.WithCancel(parentCtx) + stream, err := client.ProvideUSBDevices(streamCtx) + if err != nil { + cancel() + if c.standalone { + c.closeConnection() + } + return nil, E.Cause(err, "provide usb devices") + } + + session := &USBProviderSession{ + stream: stream, + ctx: streamCtx, + cancel: cancel, + closeDone: make(chan struct{}), + } + + standalone := c.standalone + go func() { + defer close(session.closeDone) + for { + message, recvErr := stream.Recv() + if recvErr == io.EOF { + cancel() + break + } + if recvErr != nil { + handler.OnError("", E.Cause(recvErr, "usb provider recv").Error()) + cancel() + break + } + switch payload := message.GetMessage().(type) { + case *daemon.USBServerMessage_Ready: + handler.OnReady(payload.Ready.GetDeviceId(), payload.Ready.GetBusId()) + case *daemon.USBServerMessage_UrbRequest: + handler.OnURBRequest(usbURBRequestFromGRPC(payload.UrbRequest)) + case *daemon.USBServerMessage_Abort: + handler.OnAbort(payload.Abort.GetDeviceId(), int32(payload.Abort.GetEndpoint())) + case *daemon.USBServerMessage_Error: + handler.OnError(payload.Error.GetDeviceId(), payload.Error.GetMessage()) + } + } + if standalone { + c.closeConnection() + } + }() + + return session, nil +} diff --git a/experimental/libbox/command_server.go b/experimental/libbox/command_server.go index 8c6015a16..d25f81b94 100644 --- a/experimental/libbox/command_server.go +++ b/experimental/libbox/command_server.go @@ -75,8 +75,9 @@ func NewCommandServer(handler CommandServerHandler, platformInterface PlatformIn // SystemProxyEnabled: false, }) server.managedService = daemon.NewManagedService(daemon.ManagedServiceOptions{ - Handler: (*platformHandler)(server), - Debug: sDebug, + Handler: (*platformHandler)(server), + Debug: sDebug, + OOMReporter: sOOMReporter, }) return server, nil } diff --git a/experimental/libbox/command_types_usbip.go b/experimental/libbox/command_types_usbip.go new file mode 100644 index 000000000..bcfe141bb --- /dev/null +++ b/experimental/libbox/command_types_usbip.go @@ -0,0 +1,203 @@ +package libbox + +import ( + "context" + "os" + "sync" + + "github.com/sagernet/sing-box/daemon" +) + +type USBProviderHandler interface { + OnReady(deviceID string, busID string) + OnURBRequest(request *USBURBRequest) + OnAbort(deviceID string, endpoint int32) + OnError(deviceID string, message string) +} + +type USBIsoPacket struct { + Offset int32 + Length int32 + ActualLength int32 + Status int32 +} + +type USBDeviceDescriptor struct { + ServerTag string + DeviceID string + BusNum int32 + DevNum int32 + Speed int32 + VendorID int32 + ProductID int32 + BCDDevice int32 + DeviceClass int32 + DeviceSubClass int32 + DeviceProtocol int32 + ConfigurationValue int32 + NumConfigurations int32 + Serial string + Product string + + interfaces []*daemon.USBInterface +} + +func NewUSBDeviceDescriptor(serverTag string, deviceID string) *USBDeviceDescriptor { + return &USBDeviceDescriptor{ServerTag: serverTag, DeviceID: deviceID} +} + +func (d *USBDeviceDescriptor) AddInterface(interfaceClass int32, interfaceSubClass int32, interfaceProtocol int32) { + d.interfaces = append(d.interfaces, &daemon.USBInterface{ + InterfaceClass: uint32(interfaceClass), + InterfaceSubClass: uint32(interfaceSubClass), + InterfaceProtocol: uint32(interfaceProtocol), + }) +} + +func (d *USBDeviceDescriptor) toProto() *daemon.USBDeviceAttach { + return &daemon.USBDeviceAttach{ + ServerTag: d.ServerTag, + Descriptor_: &daemon.USBDeviceDescriptor{ + DeviceId: d.DeviceID, + BusNum: uint32(d.BusNum), + DevNum: uint32(d.DevNum), + Speed: uint32(d.Speed), + VendorId: uint32(d.VendorID), + ProductId: uint32(d.ProductID), + BcdDevice: uint32(d.BCDDevice), + DeviceClass: uint32(d.DeviceClass), + DeviceSubClass: uint32(d.DeviceSubClass), + DeviceProtocol: uint32(d.DeviceProtocol), + ConfigurationValue: uint32(d.ConfigurationValue), + NumConfigurations: uint32(d.NumConfigurations), + Interfaces: d.interfaces, + Serial: d.Serial, + Product: d.Product, + }, + } +} + +type USBURBRequest struct { + DeviceID string + Seq int64 + Endpoint int32 + DirectionIn bool + TransferFlags int32 + Setup []byte + TransferBufferLength int32 + OutData []byte + NumberOfPackets int32 + StartFrame int32 + Interval int32 + + isoPackets []*daemon.USBIsoPacket +} + +func (r *USBURBRequest) IsoPacketCount() int32 { + return int32(len(r.isoPackets)) +} + +func (r *USBURBRequest) GetIsoPacket(index int32) *USBIsoPacket { + if index < 0 || int(index) >= len(r.isoPackets) { + return nil + } + packet := r.isoPackets[index] + return &USBIsoPacket{ + Offset: packet.GetOffset(), + Length: packet.GetLength(), + ActualLength: packet.GetActualLength(), + Status: packet.GetStatus(), + } +} + +func usbURBRequestFromGRPC(request *daemon.USBURBRequest) *USBURBRequest { + return &USBURBRequest{ + DeviceID: request.GetDeviceId(), + Seq: int64(request.GetSeq()), + Endpoint: int32(request.GetEndpoint()), + DirectionIn: request.GetDirectionIn(), + TransferFlags: int32(request.GetTransferFlags()), + Setup: request.GetSetup(), + TransferBufferLength: int32(request.GetTransferBufferLength()), + OutData: request.GetOutData(), + NumberOfPackets: request.GetNumberOfPackets(), + StartFrame: request.GetStartFrame(), + Interval: request.GetInterval(), + isoPackets: request.GetIsoPackets(), + } +} + +type USBURBResponse struct { + DeviceID string + Seq int64 + Status int32 + ActualLength int32 + InData []byte + + isoPackets []*daemon.USBIsoPacket +} + +func NewUSBURBResponse(deviceID string, seq int64) *USBURBResponse { + return &USBURBResponse{DeviceID: deviceID, Seq: seq} +} + +func (r *USBURBResponse) AddIsoPacket(offset int32, length int32, actualLength int32, status int32) { + r.isoPackets = append(r.isoPackets, &daemon.USBIsoPacket{ + Offset: offset, + Length: length, + ActualLength: actualLength, + Status: status, + }) +} + +func (r *USBURBResponse) toProto() *daemon.USBURBResponse { + return &daemon.USBURBResponse{ + DeviceId: r.DeviceID, + Seq: uint64(r.Seq), + Status: r.Status, + ActualLength: r.ActualLength, + InData: r.InData, + IsoPackets: r.isoPackets, + } +} + +type USBProviderSession struct { + stream daemon.StartedService_ProvideUSBDevicesClient + ctx context.Context + cancel context.CancelFunc + sendAccess sync.Mutex + closeOnce sync.Once + closeDone chan struct{} +} + +func (s *USBProviderSession) send(message *daemon.USBProviderMessage) error { + s.sendAccess.Lock() + defer s.sendAccess.Unlock() + select { + case <-s.ctx.Done(): + return os.ErrClosed + default: + } + return s.stream.Send(message) +} + +func (s *USBProviderSession) AttachDevice(descriptor *USBDeviceDescriptor) error { + return s.send(&daemon.USBProviderMessage{Message: &daemon.USBProviderMessage_Attach{Attach: descriptor.toProto()}}) +} + +func (s *USBProviderSession) DetachDevice(deviceID string) error { + return s.send(&daemon.USBProviderMessage{Message: &daemon.USBProviderMessage_Detach{Detach: &daemon.USBDeviceDetach{DeviceId: deviceID}}}) +} + +func (s *USBProviderSession) SendURBResponse(response *USBURBResponse) error { + return s.send(&daemon.USBProviderMessage{Message: &daemon.USBProviderMessage_UrbResponse{UrbResponse: response.toProto()}}) +} + +func (s *USBProviderSession) Close() error { + s.closeOnce.Do(func() { + s.cancel() + _ = s.stream.CloseSend() + }) + <-s.closeDone + return nil +} diff --git a/experimental/libbox/command_types_usbip_status.go b/experimental/libbox/command_types_usbip_status.go new file mode 100644 index 000000000..4b54ee07a --- /dev/null +++ b/experimental/libbox/command_types_usbip_status.go @@ -0,0 +1,142 @@ +package libbox + +import "github.com/sagernet/sing-box/daemon" + +type USBIPServerStatusUpdate struct { + servers []*USBIPServerStatus +} + +func (u *USBIPServerStatusUpdate) Servers() USBIPServerStatusIterator { + return newIterator(u.servers) +} + +type USBIPServerStatusIterator interface { + Next() *USBIPServerStatus + HasNext() bool +} + +type USBIPServerStatus struct { + ServerTag string + devices []*USBSharedDevice +} + +func (s *USBIPServerStatus) Devices() USBSharedDeviceIterator { + return newIterator(s.devices) +} + +type USBSharedDeviceIterator interface { + Next() *USBSharedDevice + HasNext() bool +} + +const ( + USBDeviceStateIdle int32 = iota + USBDeviceStateAttached + USBDeviceStateUnavailable +) + +const ( + USBBackendUnspecified int32 = iota + USBBackendLinuxSysfs + USBBackendDynamic + USBBackendDarwinIOKit + USBBackendWindowsVBoxUSB +) + +type USBSharedDevice struct { + BusID string + StableID string + Backend int32 + State int32 + DeviceID string + BusNum int32 + DevNum int32 + Speed int32 + VendorID int32 + ProductID int32 + BCDDevice int32 + DeviceClass int32 + DeviceSubClass int32 + DeviceProtocol int32 + ConfigurationValue int32 + NumConfigurations int32 + Serial string + Product string + interfaces []*USBSharedDeviceInterface +} + +func (d *USBSharedDevice) Interfaces() USBSharedDeviceInterfaceIterator { + return newIterator(d.interfaces) +} + +type USBSharedDeviceInterfaceIterator interface { + Next() *USBSharedDeviceInterface + HasNext() bool +} + +type USBSharedDeviceInterface struct { + InterfaceClass int32 + InterfaceSubClass int32 + InterfaceProtocol int32 +} + +type USBIPServerStatusHandler interface { + OnStatusUpdate(status *USBIPServerStatusUpdate) + OnError(message string) +} + +type USBIPServerStatusSubscription struct { + streamSession +} + +func usbipServerStatusUpdateFromGRPC(update *daemon.USBIPServerStatusUpdate) *USBIPServerStatusUpdate { + servers := make([]*USBIPServerStatus, len(update.Servers)) + for i, server := range update.Servers { + servers[i] = usbipServerStatusFromGRPC(server) + } + return &USBIPServerStatusUpdate{servers: servers} +} + +func usbipServerStatusFromGRPC(status *daemon.USBIPServerStatus) *USBIPServerStatus { + devices := make([]*USBSharedDevice, len(status.Devices)) + for i, device := range status.Devices { + devices[i] = usbSharedDeviceFromGRPC(device) + } + return &USBIPServerStatus{ + ServerTag: status.GetServerTag(), + devices: devices, + } +} + +func usbSharedDeviceFromGRPC(device *daemon.USBSharedDevice) *USBSharedDevice { + descriptor := device.GetDescriptor_() + interfaces := make([]*USBSharedDeviceInterface, len(descriptor.GetInterfaces())) + for i, deviceInterface := range descriptor.GetInterfaces() { + interfaces[i] = &USBSharedDeviceInterface{ + InterfaceClass: int32(deviceInterface.GetInterfaceClass()), + InterfaceSubClass: int32(deviceInterface.GetInterfaceSubClass()), + InterfaceProtocol: int32(deviceInterface.GetInterfaceProtocol()), + } + } + return &USBSharedDevice{ + BusID: device.GetBusId(), + StableID: device.GetStableId(), + Backend: int32(device.GetBackend()), + State: int32(device.GetState()), + DeviceID: descriptor.GetDeviceId(), + BusNum: int32(descriptor.GetBusNum()), + DevNum: int32(descriptor.GetDevNum()), + Speed: int32(descriptor.GetSpeed()), + VendorID: int32(descriptor.GetVendorId()), + ProductID: int32(descriptor.GetProductId()), + BCDDevice: int32(descriptor.GetBcdDevice()), + DeviceClass: int32(descriptor.GetDeviceClass()), + DeviceSubClass: int32(descriptor.GetDeviceSubClass()), + DeviceProtocol: int32(descriptor.GetDeviceProtocol()), + ConfigurationValue: int32(descriptor.GetConfigurationValue()), + NumConfigurations: int32(descriptor.GetNumConfigurations()), + Serial: descriptor.GetSerial(), + Product: descriptor.GetProduct(), + interfaces: interfaces, + } +} diff --git a/go.mod b/go.mod index 27d308f9c..e6a9e499b 100644 --- a/go.mod +++ b/go.mod @@ -146,6 +146,7 @@ require ( github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260620135226-def9ff0fb992 // indirect github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/sagernet/nftables v0.3.0-mod.2 // indirect + github.com/sagernet/sing-usbip v0.0.0-20260615120724-630651f2af95 github.com/spf13/pflag v1.0.9 // indirect github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect diff --git a/go.sum b/go.sum index dc5ad8e44..0bb9e176b 100644 --- a/go.sum +++ b/go.sum @@ -268,6 +268,8 @@ github.com/sagernet/sing-shadowtls v0.2.1 h1:ZiHZdnEnP+YS73NMsxiZmIFCwNd0M4k7PkG github.com/sagernet/sing-shadowtls v0.2.1/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA= github.com/sagernet/sing-tun v0.8.12-0.20260623031040-54c9dbda5fe7 h1:UZu+fMnbfOJ14v7eXQe0UADNiPkR7gO70BsDFtLXZbg= github.com/sagernet/sing-tun v0.8.12-0.20260623031040-54c9dbda5fe7/go.mod h1:QvarqUtHfj1ULaRR+6kZOS/OoCE+pYGq67A5tyIy+dQ= +github.com/sagernet/sing-usbip v0.0.0-20260615120724-630651f2af95 h1:1z+EwDwim2C1Lt5HRRFeT8MbvEKxb/LSz/F0vbBwm6g= +github.com/sagernet/sing-usbip v0.0.0-20260615120724-630651f2af95/go.mod h1:D4CnJX3MNAAANhbQUxfIRgBdnvlTEaV7h6ojedcs+pw= github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 h1:aSwUNYUkVyVvdmBSufR8/nRFonwJeKSIROxHcm5br9o= github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1/go.mod h1:P11scgTxMxVVQ8dlM27yNm3Cro40mD0+gHbnqrNGDuY= github.com/sagernet/smux v1.5.50-sing-box-mod.1 h1:XkJcivBC9V4wBjiGXIXZ229aZCU1hzcbp6kSkkyQ478= diff --git a/include/registry.go b/include/registry.go index 330519c84..3bcbddb36 100644 --- a/include/registry.go +++ b/include/registry.go @@ -143,6 +143,7 @@ func ServiceRegistry() *service.Registry { registerCCMService(registry) registerOCMService(registry) registerOOMKillerService(registry) + registerUSBIPServices(registry) return registry } diff --git a/include/usbip.go b/include/usbip.go new file mode 100644 index 000000000..c6b7b2032 --- /dev/null +++ b/include/usbip.go @@ -0,0 +1,12 @@ +//go:build with_usbip && (linux || (darwin && cgo) || windows) + +package include + +import ( + "github.com/sagernet/sing-box/adapter/service" + "github.com/sagernet/sing-box/service/usbip" +) + +func registerUSBIPServices(registry *service.Registry) { + usbip.RegisterService(registry) +} diff --git a/include/usbip_stub.go b/include/usbip_stub.go new file mode 100644 index 000000000..758748575 --- /dev/null +++ b/include/usbip_stub.go @@ -0,0 +1,23 @@ +//go:build !with_usbip || !(linux || (darwin && cgo) || windows) + +package include + +import ( + "context" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/adapter/service" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + E "github.com/sagernet/sing/common/exceptions" +) + +func registerUSBIPServices(registry *service.Registry) { + service.Register[option.USBIPServerServiceOptions](registry, C.TypeUSBIPServer, func(ctx context.Context, logger log.ContextLogger, tag string, options option.USBIPServerServiceOptions) (adapter.Service, error) { + return nil, E.New(`USB/IP is not included in this build, rebuild with -tags with_usbip (supported on Linux, Windows, and macOS with CGO)`) + }) + service.Register[option.USBIPClientServiceOptions](registry, C.TypeUSBIPClient, func(ctx context.Context, logger log.ContextLogger, tag string, options option.USBIPClientServiceOptions) (adapter.Service, error) { + return nil, E.New(`USB/IP is not included in this build, rebuild with -tags with_usbip (supported on Linux, Windows, and macOS with CGO)`) + }) +} diff --git a/option/usbip.go b/option/usbip.go new file mode 100644 index 000000000..cdfcb107d --- /dev/null +++ b/option/usbip.go @@ -0,0 +1,69 @@ +package option + +import ( + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/json" + "github.com/sagernet/sing/common/json/badjson" +) + +const ( + USBIPProviderDefault = "default" + USBIPProviderDynamic = "dynamic" +) + +type _USBIPServerServiceOptions struct { + ListenOptions + Provider string `json:"provider,omitempty"` + Options any `json:"-"` +} + +type USBIPServerServiceOptions _USBIPServerServiceOptions + +func (o USBIPServerServiceOptions) MarshalJSON() ([]byte, error) { + if o.Options == nil { + return json.Marshal((_USBIPServerServiceOptions)(o)) + } + return badjson.MarshallObjects((_USBIPServerServiceOptions)(o), o.Options) +} + +func (o *USBIPServerServiceOptions) UnmarshalJSON(content []byte) error { + err := json.Unmarshal(content, (*_USBIPServerServiceOptions)(o)) + if err != nil { + return err + } + var options any + switch o.Provider { + case "", USBIPProviderDefault: + o.Provider = USBIPProviderDefault + options = new(USBIPDefaultProviderOptions) + case USBIPProviderDynamic: + options = new(USBIPDynamicProviderOptions) + default: + return E.New("unknown usbip provider type: ", o.Provider) + } + err = badjson.UnmarshallExcluded(content, (*_USBIPServerServiceOptions)(o), options) + if err != nil { + return err + } + o.Options = options + return nil +} + +type USBIPClientServiceOptions struct { + DialerOptions + Server string `json:"server,omitempty"` + Devices []USBIPDeviceMatch `json:"devices,omitempty"` +} + +type USBIPDeviceMatch struct { + BusID string `json:"bus_id,omitempty"` + VendorID uint16 `json:"vendor_id,omitempty"` + ProductID uint16 `json:"product_id,omitempty"` + Serial string `json:"serial,omitempty"` +} + +type USBIPDefaultProviderOptions struct { + Devices []USBIPDeviceMatch `json:"devices,omitempty"` +} + +type USBIPDynamicProviderOptions struct{} diff --git a/release/DEFAULT_BUILD_TAGS b/release/DEFAULT_BUILD_TAGS index e06bc120e..4754ec449 100644 --- a/release/DEFAULT_BUILD_TAGS +++ b/release/DEFAULT_BUILD_TAGS @@ -1 +1 @@ -with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_cloudflared,with_naive_outbound,badlinkname,tfogo_checklinkname0 \ No newline at end of file +with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_cloudflared,with_naive_outbound,with_usbip,badlinkname,tfogo_checklinkname0 \ No newline at end of file diff --git a/release/DEFAULT_BUILD_TAGS_OTHERS b/release/DEFAULT_BUILD_TAGS_OTHERS index a28e900e9..db8a0c340 100644 --- a/release/DEFAULT_BUILD_TAGS_OTHERS +++ b/release/DEFAULT_BUILD_TAGS_OTHERS @@ -1 +1 @@ -with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_cloudflared,badlinkname,tfogo_checklinkname0 \ No newline at end of file +with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_cloudflared,with_usbip,badlinkname,tfogo_checklinkname0 \ No newline at end of file diff --git a/release/DEFAULT_BUILD_TAGS_WINDOWS b/release/DEFAULT_BUILD_TAGS_WINDOWS index af4fe4162..d63a3967f 100644 --- a/release/DEFAULT_BUILD_TAGS_WINDOWS +++ b/release/DEFAULT_BUILD_TAGS_WINDOWS @@ -1 +1 @@ -with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_cloudflared,with_naive_outbound,with_purego,badlinkname,tfogo_checklinkname0 \ No newline at end of file +with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_cloudflared,with_naive_outbound,with_purego,with_usbip,badlinkname,tfogo_checklinkname0 \ No newline at end of file diff --git a/service/usbip/client.go b/service/usbip/client.go new file mode 100644 index 000000000..049573ca7 --- /dev/null +++ b/service/usbip/client.go @@ -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() +} diff --git a/service/usbip/server.go b/service/usbip/server.go new file mode 100644 index 000000000..81e65bb60 --- /dev/null +++ b/service/usbip/server.go @@ -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) +} diff --git a/service/usbip/service.go b/service/usbip/service.go new file mode 100644 index 000000000..ccf70e3d8 --- /dev/null +++ b/service/usbip/service.go @@ -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 +} diff --git a/service/usbip/stub.go b/service/usbip/stub.go new file mode 100644 index 000000000..a10ef1a6e --- /dev/null +++ b/service/usbip/stub.go @@ -0,0 +1,3 @@ +//go:build !with_usbip || !(linux || (darwin && cgo) || windows) + +package usbip