Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deal with a limit on the number of active connections #342

Open
gfwilliams opened this issue Dec 19, 2016 · 5 comments
Open

Deal with a limit on the number of active connections #342

gfwilliams opened this issue Dec 19, 2016 · 5 comments

Comments

@gfwilliams
Copy link

Hi,

Not sure if this is the right place, but please can I request a minor tweak to the Web Bluetooth spec? To make BluetoothRemoteGATTServer.disconnect return a promise (it should break anything).

At least on some platforms, disconnection seems to take a certain amount of time, and there are limits to the amount of active BLE connections.

I can totally imagine a situation where someone is trying to work their way around several Bluetooth devices that they have previously requested access to, and they're disconnecting from one device and connecting to another - but they'd be forced to add an arbitrary timeout so as not to go past the hardware/OS's connection limit.

This is exactly the issue I'm having with puck.js right now - I'm trying to implement a web bluetooth compliant API on the hardware, but as it is currently there can only be one outgoing connection. Users are having to manually add a ~200ms timeout to ensure that they can connect to a new device after calling disconnect.

thanks!

@Emill
Copy link

Emill commented Dec 20, 2016

Your problem scenario is indeed valid. It is hard for an app to know when a connection will success or fail if the maximum number of connections is reached or almost reached.

When a disconnection is initiated, an LL_TERMINATE_IND packet is sent to the remote device. The disconnecting device must wait for a link layer acknowledgement of this packet (or timeout) until this connection is considered disconnected. So, the time to disconnect depends on the connection interval, slave latency and supervision timeout. The time to disconnect can in worst case take 32 seconds, which corresponds to the longest possible supervision timeout. Under normal circumstances however the time to disconnect is usually limited by the connection interval * (slave latency + 1).

Making disconnect promise-based is not as easy as it may sound, due to the fact that most GATT implementations offer a way to have multiple logical connections on the same physical connection. You can for example have two Android apps talking to the same BLE peripheral over a single physical GATT link. The peripheral "thinks" there is only one client at the other end. When you disconnect, you only disconnect the logical link, which is done immediately. The physical link will be kept open until all logical clients have disconnected. iOS, Android and Windows also adds some additional seconds after the last client disconnected until the actual link gets terminated. So when do you want your promise to resolve?

At least Android and Windows have global broadcasts you can listen to in order to know when physical links get disconnected which can be good in certain cases. But they are not exposed to Web Bluetooth...

Unfortunately, no platforms I'm aware of have well-defined behaviour nor documented APIs to handle the case when the maximum number of connections is reached. It seems people working on Bluetooth stacks have not really thought, cared about or even tested what will or should happen if users have many BLE devices. As an example, the Bluetooth stack in Android hangs if you have 7 BLE connections and try to establish the 8th with "autoConnect=true" (in the way that it will never again connect to BLE devices until Bluetooth is restarted, even if the 7 get disconnected). If you have GATT notifications you listen to in Windows and are above the maximum number of connections, you get no event telling this, so some notifications will not be delivered to your computer (since the peripheral can't connect). Generally among most platforms some random error code is thrown (general failure, internal error, unspecified error, gatt error) when you actively try to connect a new device when the maximum number of connections has been reached. Sometimes a better error code like "no resources" is thrown. The non-existing documentation of error codes that is unfortunately general among all BLE implementations is very annoying when you are an app developer (Windows must be the worst when they're trying to map BLE errors to their general 0x80... HRESULT error codes).

In the fliclib-linux-hci project I created (https://github.com/50ButtonsEach/fliclib-linux-hci/blob/master/ProtocolDocumentation.md), which is a GATT client implementation, acting as a TCP server, you can connect multiple TCP clients, having multiple logical connections for the same physical connection. Here I solved the maximum number of connections problem by having two events that are sent to all clients: EvtNoSpaceForNewConnection and EvtGotSpaceForNewConnection. EvtNoSpaceForNewConnection is sent when the maximum number of connections has been reached and EvtGotSpaceForNewConnection is sent when one physical link has been disconnected if the maximum number of connections was previously reached. Usually the programmer doesn't need to react to those events except from notifying the user, since in that implementation, there is also no way a connection attempt can return a failure status (except when also the white list is full, which is usually of size 128 and I guess no one reaches). It will simply try to connect forever until success.

@jyasskin
Copy link
Member

This sounds like a real problem, but @Emill points out good reasons not to solve it by having disconnect() return a promise.
Having the "no space" and "got space" events sounds like a reasonably good solution, but we can't really add them to the spec unless we can implement them on most platforms. How would we do it on Android, BlueZ, Mac, and Windows?

@gfwilliams
Copy link
Author

I'm afraid I'm well past my knowledge of BLE implementations at this point.

From my point of view, 'no space'/etc isn't particularly easy for people to use in the disconnect then connect case - which is what I'd hoped to address... And I wonder if it's really that much easier or more efficient than just repeatedly trying to reconnect every second until something works.

To be fair the only reason it's an issue for me is because Puck.js only allows one active connection - personally I think it might be worth closing this issue. I'm sure the Google engineers' time is much better spent on other things (windows support? ;) )

@jyasskin
Copy link
Member

Another approach would be to have connect() reject its promise with "connection limit reached", and then you'd wait for a global "got space" event before trying again. It sounds like we can't implement that (or maybe any "limit reached" notification) on Android, though.

@jyasskin jyasskin changed the title BluetoothRemoteGATTServer.disconnect could return a promise Deal with a limit on the number of active connections Jan 20, 2017
@gfwilliams
Copy link
Author

Yes - a recognisable rejection message (if possible) from connect would be great.

A 'got space' event would be nice, but I don't think that's absolutely required. It could just keep trying every few seconds - not ideal, but I think it's probably quite a rare case anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants