Files
sing-box/service/usbip/control_server.go
T
2026-06-09 10:42:25 +08:00

135 lines
3.7 KiB
Go

//go:build linux || (darwin && cgo)
package usbip
import (
"net"
)
type serverControlConn struct {
id uint64
capabilities uint32
conn net.Conn
send chan controlMessage
}
func (s *ServerService) registerControlConn(conn net.Conn, capabilities uint32) (*serverControlConn, uint64) {
s.controlAccess.Lock()
defer s.controlAccess.Unlock()
s.controlNextID++
sequence := s.controlSeq
sub := &serverControlConn{
id: s.controlNextID,
capabilities: capabilities,
conn: conn,
send: make(chan controlMessage, 16),
}
if supportsControlExtensions(capabilities) {
s.enqueueControlSnapshot(sub, sequence)
}
s.controlSubs[sub.id] = sub
return sub, sequence
}
func (s *ServerService) unregisterControlConn(id uint64) {
s.controlAccess.Lock()
defer s.controlAccess.Unlock()
delete(s.controlSubs, id)
s.deleteImportLeasesForSubscriberLocked(id)
}
func (s *ServerService) closeControlSubscribers() {
s.controlAccess.Lock()
subs := make([]*serverControlConn, 0, len(s.controlSubs))
for _, sub := range s.controlSubs {
subs = append(subs, sub)
}
s.controlSubs = make(map[uint64]*serverControlConn)
s.controlAccess.Unlock()
for _, sub := range subs {
_ = sub.conn.Close()
}
}
func (s *ServerService) broadcastControlState(nextState map[string]DeviceInfoV2, force bool) bool {
s.controlAccess.Lock()
nextSequence := s.controlSeq + 1
delta := buildControlDeviceDelta(nextSequence, s.controlState, nextState)
if !force && controlDeviceDeltaEmpty(delta) {
s.controlState = nextState
s.controlAccess.Unlock()
return false
}
s.controlSeq = nextSequence
sequence := s.controlSeq
s.controlState = nextState
subs := make([]*serverControlConn, 0, len(s.controlSubs))
for _, sub := range s.controlSubs {
subs = append(subs, sub)
}
s.controlAccess.Unlock()
frame := controlFrame{
Type: controlFrameChanged,
Version: controlProtocolVersion,
Sequence: sequence,
}
for _, sub := range subs {
if supportsControlExtensions(sub.capabilities) {
s.enqueueControlPayload(sub, controlFrame{
Type: controlFrameDeviceDelta,
Version: controlProtocolVersion,
Sequence: sequence,
}, delta, frame)
continue
}
s.enqueueControlFrame(sub, frame)
}
return true
}
func (s *ServerService) enqueueControlFrame(sub *serverControlConn, frame controlFrame) {
s.enqueueControlMessage(sub, controlMessage{Frame: frame})
}
func (s *ServerService) enqueueControlPayload(sub *serverControlConn, frame controlFrame, payload any, fallback controlFrame) {
rawPayload, err := marshalControlPayload(payload)
if err != nil || len(rawPayload) > maxControlPayloadLength {
s.enqueueControlFrame(sub, fallback)
return
}
s.enqueueControlMessage(sub, controlMessage{Frame: frame, Payload: rawPayload})
}
func (s *ServerService) enqueueControlSnapshot(sub *serverControlConn, sequence uint64) {
devices := s.buildDeviceStateV2()
s.enqueueControlPayload(sub, controlFrame{
Type: controlFrameDeviceSnapshot,
Version: controlProtocolVersion,
Sequence: sequence,
}, controlDeviceSnapshot{Sequence: sequence, Devices: devices}, controlFrame{
Type: controlFrameChanged,
Version: controlProtocolVersion,
Sequence: sequence,
})
}
func (s *ServerService) enqueueControlMessage(sub *serverControlConn, message controlMessage) {
select {
case sub.send <- message:
default:
s.logger.Debug("control subscriber ", sub.id, " lagged behind")
_ = sub.conn.Close()
}
}
func (s *ServerService) refreshControlState() {
s.setControlState(deviceInfoV2Map(s.buildDeviceStateV2()))
}
func (s *ServerService) setControlState(nextState map[string]DeviceInfoV2) {
s.controlAccess.Lock()
s.controlState = nextState
s.controlAccess.Unlock()
}