Skip to content

Commit 314bd2b

Browse files
Lenart12deadprogram
authored andcommitted
linux: call startDiscovery async as it can block if adapter powered off
1 parent 690630b commit 314bd2b

File tree

2 files changed

+42
-25
lines changed

2 files changed

+42
-25
lines changed

gap.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
var (
99
errScanning = errors.New("bluetooth: a scan is already in progress")
1010
errNotScanning = errors.New("bluetooth: there is no scan in progress")
11+
errScanStopped = errors.New("bluetooth: scan was stopped unexpectedly")
1112
errAdvertisementPacketTooBig = errors.New("bluetooth: advertisement packet overflows")
1213
errNotYetImplmented = errors.New("bluetooth: not implemented")
1314
)

gap_linux.go

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,27 @@ func (a *Adapter) Scan(callback func(*Adapter, ScanResult)) error {
142142
return errScanning
143143
}
144144

145+
signal := make(chan *dbus.Signal)
146+
a.bus.Signal(signal)
147+
defer a.bus.RemoveSignal(signal)
148+
149+
propertiesChangedMatchOptions := []dbus.MatchOption{dbus.WithMatchInterface("org.freedesktop.DBus.Properties")}
150+
a.bus.AddMatchSignal(propertiesChangedMatchOptions...)
151+
defer a.bus.RemoveMatchSignal(propertiesChangedMatchOptions...)
152+
153+
newObjectMatchOptions := []dbus.MatchOption{dbus.WithMatchInterface("org.freedesktop.DBus.ObjectManager")}
154+
a.bus.AddMatchSignal(newObjectMatchOptions...)
155+
defer a.bus.RemoveMatchSignal(newObjectMatchOptions...)
156+
157+
// Check if the adapter is powered on.
158+
powered, err := a.adapter.GetProperty("org.bluez.Adapter1.Powered")
159+
if err != nil {
160+
return err
161+
}
162+
if !powered.Value().(bool) {
163+
return errAdaptorNotPowered
164+
}
165+
145166
// Channel that will be closed when the scan is stopped.
146167
// Detecting whether the scan is stopped can be done by doing a non-blocking
147168
// read from it. If it succeeds, the scan is stopped.
@@ -150,25 +171,13 @@ func (a *Adapter) Scan(callback func(*Adapter, ScanResult)) error {
150171

151172
// This appears to be necessary to receive any BLE discovery results at all.
152173
defer a.adapter.Call("org.bluez.Adapter1.SetDiscoveryFilter", 0)
153-
err := a.adapter.Call("org.bluez.Adapter1.SetDiscoveryFilter", 0, map[string]interface{}{
174+
err = a.adapter.Call("org.bluez.Adapter1.SetDiscoveryFilter", 0, map[string]interface{}{
154175
"Transport": "le",
155176
}).Err
156177
if err != nil {
157178
return err
158179
}
159180

160-
signal := make(chan *dbus.Signal)
161-
a.bus.Signal(signal)
162-
defer a.bus.RemoveSignal(signal)
163-
164-
propertiesChangedMatchOptions := []dbus.MatchOption{dbus.WithMatchInterface("org.freedesktop.DBus.Properties")}
165-
a.bus.AddMatchSignal(propertiesChangedMatchOptions...)
166-
defer a.bus.RemoveMatchSignal(propertiesChangedMatchOptions...)
167-
168-
newObjectMatchOptions := []dbus.MatchOption{dbus.WithMatchInterface("org.freedesktop.DBus.ObjectManager")}
169-
a.bus.AddMatchSignal(newObjectMatchOptions...)
170-
defer a.bus.RemoveMatchSignal(newObjectMatchOptions...)
171-
172181
// Go through all connected devices and present the connected devices as
173182
// scan results. Also save the properties so that the full list of
174183
// properties is known on a PropertiesChanged signal. We can't present the
@@ -200,10 +209,9 @@ func (a *Adapter) Scan(callback func(*Adapter, ScanResult)) error {
200209
}
201210

202211
// Instruct BlueZ to start discovering.
203-
err = a.adapter.Call("org.bluez.Adapter1.StartDiscovery", 0).Err
204-
if err != nil {
205-
return err
206-
}
212+
// NOTE: We must call Go here, not Call, because it can block if adapter is
213+
// powered off, or was recently powered off.
214+
startDiscovery := a.adapter.Go("org.bluez.Adapter1.StartDiscovery", 0, nil)
207215

208216
for {
209217
// Check whether the scan is stopped. This is necessary to avoid a race
@@ -217,6 +225,12 @@ func (a *Adapter) Scan(callback func(*Adapter, ScanResult)) error {
217225
}
218226

219227
select {
228+
case <-startDiscovery.Done:
229+
if startDiscovery.Err != nil {
230+
close(cancelChan)
231+
a.scanCancelChan = nil
232+
return startDiscovery.Err
233+
}
220234
case sig := <-signal:
221235
// This channel receives anything that we watch for, so we'll have
222236
// to check for signals that are relevant to us.
@@ -236,14 +250,16 @@ func (a *Adapter) Scan(callback func(*Adapter, ScanResult)) error {
236250
case "org.bluez.Adapter1":
237251
// check power state
238252
changes := sig.Body[1].(map[string]dbus.Variant)
239-
for k, v := range changes {
240-
if k == "Powered" && !v.Value().(bool) {
241-
// adapter is powered off, stop the scan
242-
close(cancelChan)
243-
close(a.scanCancelChan)
244-
a.scanCancelChan = nil
245-
return errAdaptorNotPowered
246-
}
253+
if powered, ok := changes["Powered"]; ok && !powered.Value().(bool) {
254+
// adapter is powered off, stop the scan
255+
close(cancelChan)
256+
a.scanCancelChan = nil
257+
return errAdaptorNotPowered
258+
} else if discovering, ok := changes["Discovering"]; ok && !discovering.Value().(bool) {
259+
// adapter stopped discovering unexpectedly (e.g. due to external event)
260+
close(cancelChan)
261+
a.scanCancelChan = nil
262+
return errScanStopped
247263
}
248264

249265
case "org.bluez.Device1":

0 commit comments

Comments
 (0)