consrv does not gracefully handle disappearing / re-appearing serial device
stapelberg opened this issue · 1 comments
In my setup, for whichever reason, the USB-to-serial adapter occasionally drops off the USB bus and comes back as ttyUSB1
instead of ttyUSB0
:
[776891.671139] cp210x ttyUSB1: usb_serial_generic_read_bulk_callback - urb stopped: -32
[776891.680238] cp210x ttyUSB1: usb_serial_generic_read_bulk_callback - urb stopped: -32
[776891.764819] usb 1-1-port3: disabled by hub (EMI?), re-enabling...
[776891.772885] usb 1-1.3: USB disconnect, device number 6
[776891.779671] cp210x ttyUSB1: failed set request 0x12 status: -19
[776891.786843] cp210x ttyUSB1: failed set request 0x0 status: -19
[776891.794229] cp210x ttyUSB1: cp210x converter now disconnected from ttyUSB1
[776891.802492] cp210x 1-1.3:1.0: device disconnected
[776892.031977] usb 1-1.3: new full-speed USB device number 7 using dwc2
[776892.143732] cp210x 1-1.3:1.0: cp210x converter detected
[776892.151568] usb 1-1.3: cp210x converter now attached to ttyUSB0
I don’t know yet if this correlates to any specific trigger (perhaps rebooting my router?), but it happens frequently enough to be noticeable.
This behavior can be reproduced by physically un-plugging the USB-to-serial adapter and plugging it back in.
On the Go side, the symptom is that Read() returns an io.EOF error.
Currently, consrv connections just hang indefinitely until you send a byte, which triggers a write to the ttyUSB0
device, which triggers a write /dev/ttyUSB1: input/output error
that then closes the SSH session.
There are a number of things subtly wrong that result in the silent swallowing of the error. I can send a PR that addresses enough of them to make the SSH session close immediately when un-plugging the adapter.
What’s still left to be done is closing the mux device and underlying serial port, and then re-opening it on the next connection.
What’s still left to be done is closing the mux device and underlying serial port, and then re-opening it on the next connection.
A pragmatic workaround for this is to enable logtostdout (see PR #5) and make consrv log.Fatalf when reading EOF:
diff --git i/cmd/consrv/main.go w/cmd/consrv/main.go
index da918a0..18cef58 100644
--- i/cmd/consrv/main.go
+++ w/cmd/consrv/main.go
@@ -119,6 +119,10 @@ func main() {
if err := scanner.Err(); err != nil {
ll.Printf("copying serial to stdout: %v", err)
}
+ // io.EOF (not considered an error by scanner.Err()) is
+ // unexpected here, as we expect an infinite serial
+ // stream. Encountering io.EOF means the device has disappeared.
+ log.Fatalf("device disappeared: %s", d.Name)
}()
}
}
When unplugging the serial adapter, consrv starts crashlooping until the adapter is plugged back in.
Obviously this is only doable when you have precisely 1 serial adapter you care about, otherwise the failure of one results in all other adapters being unavailable, too.