Files
sing-box/service/usbip/server_shared.go
T
世界 ea57b1c928 usbip: drop low-quality abstractions and mock-based tests
Remove four private single-impl interfaces (usbEventListener,
darwinUSBHostDeviceWatch, darwinServerDataDevice, darwinEndpointStateMachine)
and both function-table DI seams (usbipOps, darwinServerOps); production calls
the underlying functions directly. Inline ~25 single-call helpers and fuse
subordinate routines into their sole caller. Collapse single-field helper
structs into their underlying types. Fold server_linux.go/server_darwin.go
into host_linux.go/host_darwin.go.

Delete change-detector tests per .claude/rules/code-test.md: parse round-trip,
mirror, input-validation, and builder-property suites that never exercised
real syscalls, network, or cgo. Six test files removed; linux_test.go slimmed
to three real-system tests; darwin_integration_test.go retains the six
real-cgo tests. Surviving suite: 16 tests that all exercise real OS APIs or
spawn the official Linux usbip server.

Net: -5100 LoC (~37% of the package).
2026-06-09 10:42:27 +08:00

81 lines
1.7 KiB
Go

//go:build linux || (darwin && cgo)
package usbip
import (
"bytes"
"io"
"net"
"time"
E "github.com/sagernet/sing/common/exceptions"
)
func (s *ServerService) acceptLoop(ln net.Listener) {
for {
conn, err := ln.Accept()
if err != nil {
select {
case <-s.ctx.Done():
return
default:
}
if E.IsClosed(err) {
return
}
//nolint:staticcheck // net.Error.Temporary predates net.ErrClosed; replacement needs a separate audit.
if netError, isNetError := err.(net.Error); isNetError && netError.Temporary() {
s.logger.Error("accept: ", err)
if !sleepCtx(s.ctx, 200*time.Millisecond) {
return
}
continue
}
s.logger.Error("accept: ", err)
return
}
go s.dispatchConn(conn)
}
}
func (s *ServerService) dispatchConn(conn net.Conn) {
var prefix [controlPrefaceSize]byte
if _, err := io.ReadFull(conn, prefix[:]); err != nil {
s.logger.Debug("read connection preface: ", err)
_ = conn.Close()
return
}
if bytes.Equal(prefix[:], controlPreface[:]) {
s.handleControlConn(conn)
return
}
s.handleStandardConn(conn, ParseOpHeader(prefix[:]))
}
func (s *ServerService) readControlConn(sub *exportSubscriber, done chan<- struct{}) {
defer close(done)
var reader controlReader
for {
message, err := reader.read(sub.conn)
if err != nil {
return
}
frame := message.Frame
switch frame.Type {
case controlFramePing:
s.ledger.enqueueFrame(sub, controlFrame{
Type: controlFramePong,
Version: controlProtocolVersion,
})
case controlFrameLeaseRequest:
if supportsControlExtensions(sub.capabilities) {
s.ledger.HandleControlLeaseRequest(s.ctx, sub, message.Payload)
continue
}
return
default:
return
}
}
}