Unverified Commit fd3e6c73 authored by Eric Stutzenberger's avatar Eric Stutzenberger Committed by GitHub
Browse files

Merge pull request #5 from rigado/fix/failed_send

Emergency timeout for failed HCI sends
parents 53fc7ac0 5c64eb90
......@@ -259,12 +259,34 @@ func (h *HCI) send(c Command) ([]byte, error) {
h.close(fmt.Errorf("hci: failed to send whole cmd pkt to hci socket"))
}
var ret []byte
var err error
// emergency timeout to prevent calls from locking up if the HCI
// interface doesn't respond. Responsed here should normally be fast
// a timeout indicates a major problem with HCI.
timeout := time.NewTimer(10 * time.Second)
select {
case <-timeout.C:
err = fmt.Errorf("hci: no response to command, hci connection failed")
ret = nil
case <-h.done:
return nil, h.err
err = h.err
ret = nil
case b := <-p.done:
return b, nil
err = nil
ret = b
}
timeout.Stop()
// clear sent table when done, we sometimes get command complete or
// command status messages with no matching send, which can attempt to
// access stale packets in sent and fail or lock up.
h.muSent.Lock()
delete(h.sent, c.OpCode())
h.muSent.Unlock()
return ret, err
}
func (h *HCI) sktLoop() {
......@@ -273,7 +295,11 @@ func (h *HCI) sktLoop() {
for {
n, err := h.skt.Read(b)
if n == 0 || err != nil {
h.err = fmt.Errorf("skt: %s", err)
if err == io.EOF {
h.err = err //callers depend on detecting io.EOF, don't wrap it.
} else {
h.err = fmt.Errorf("skt: %s", err)
}
return
}
p := make([]byte, n)
......@@ -561,4 +587,3 @@ func (h *HCI) setAllowedCommands(n int) {
h.chCmdBufs <- make([]byte, 64) // TODO make buffer size a constant
}
}
......@@ -119,14 +119,21 @@ func open(fd, id int) (*Socket, error) {
}
func (s *Socket) Read(p []byte) (int, error) {
s.rmu.Lock()
n, err := unix.Read(s.fd, p)
s.rmu.Unlock()
// Close always sends a dummy command to wake up Read
// bad things happen to the HCI state machines if they receive
// a reply from that command, so make sure no data is returned
// on a closed socket.
//
// note that if Write and Close are called concurrently it's
// indeterminate which replies get through.
select {
case <-s.closed:
return 0, io.EOF
default:
}
s.rmu.Lock()
defer s.rmu.Unlock()
n, err := unix.Read(s.fd, p)
return n, errors.Wrap(err, "can't read hci socket")
}
......@@ -139,7 +146,7 @@ func (s *Socket) Write(p []byte) (int, error) {
func (s *Socket) Close() error {
close(s.closed)
s.Write([]byte{0x01, 0x09, 0x10, 0x00})
s.Write([]byte{0x01, 0x09, 0x10, 0x00}) // no-op command to wake up the Read call if it's blocked
s.rmu.Lock()
defer s.rmu.Unlock()
return errors.Wrap(unix.Close(s.fd), "can't close hci socket")
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment