diff --git a/bin/usb-client b/bin/usb-client index 9dea612..e096a5a 100755 Binary files a/bin/usb-client and b/bin/usb-client differ diff --git a/bin/usb-client.exe b/bin/usb-client.exe index 4f9fe46..1badc81 100755 Binary files a/bin/usb-client.exe and b/bin/usb-client.exe differ diff --git a/bin/usb-relay b/bin/usb-relay index dcd01b9..fbe145f 100755 Binary files a/bin/usb-relay and b/bin/usb-relay differ diff --git a/internal/client/share.go b/internal/client/share.go index 1551e51..4773df4 100644 --- a/internal/client/share.go +++ b/internal/client/share.go @@ -306,8 +306,9 @@ func (sm *ShareManager) handleReleaseDevice(busID, fromClient string) { // Notify client sm.client.SendJSON(&protocol.DeviceReleased{ - Type: protocol.MsgDeviceReleased, - BusID: busID, + Type: protocol.MsgDeviceReleased, + BusID: busID, + ClientID: sm.client.ID(), }) log.Printf("[share] device %s released", busID) diff --git a/internal/client/use.go b/internal/client/use.go index 12c0a35..39975a3 100644 --- a/internal/client/use.go +++ b/internal/client/use.go @@ -425,6 +425,38 @@ func (um *UseManager) handleDeviceDenied(msg *protocol.DeviceDenied) { func (um *UseManager) handleDeviceReleased(msg *protocol.DeviceReleased) { log.Printf("[use] device released by share client: %s", msg.BusID) + + um.mu.Lock() + // Find and clean up any attached device matching this BusID (and ClientID if provided) + for key, dev := range um.attached { + if dev.BusID != msg.BusID { + continue + } + if msg.ClientID != "" && dev.ClientID != msg.ClientID { + continue + } + + // Clean up tunnel + if tunnel, ok := um.tunnels[dev.TunnelID]; ok { + close(tunnel.done) + if tunnel.conn != nil { + tunnel.conn.Close() + } + delete(um.tunnels, dev.TunnelID) + } + + // Detach from VHCI + if dev.VHCIPort >= 0 { + if err := usbip.DetachDevice(dev.VHCIPort); err != nil { + log.Printf("[use] warning: VHCI detach error for force-released device: %v", err) + } + } + + delete(um.attached, key) + log.Printf("[use] device %s cleaned up (force-released by share client)", key) + break + } + um.mu.Unlock() } func (um *UseManager) handleTunnelData(tunnelID string, data []byte) { diff --git a/internal/protocol/messages.go b/internal/protocol/messages.go index 5b52330..175a00e 100644 --- a/internal/protocol/messages.go +++ b/internal/protocol/messages.go @@ -106,8 +106,9 @@ type ReleaseDevice struct { // DeviceReleased is sent when a device is released type DeviceReleased struct { - Type string `json:"type"` - BusID string `json:"bus_id"` + Type string `json:"type"` + BusID string `json:"bus_id"` + ClientID string `json:"client_id,omitempty"` } // ForceRelease is sent by use clients to force-release a device from another user