ea57b1c928
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).
81 lines
1.7 KiB
Go
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
|
|
}
|
|
}
|
|
}
|