From 7850f58d81c2262cc52baa72cf05de7e24a73588 Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Sun, 31 May 2020 05:21:54 +0200
Subject: Differentiate disconnect w/ IO-Error, i.e. DBTDevice shall not issue
HCI nor Mgmt disconnect (device gone)
It has shown that the extreme 6-9s delay in forced disconnect (device shutdown)
is caused by the HCI and Mgmt disconnect command. Both fail, always.
Hence, in case of a GATT send error or short read-reply timeout (ringbuffer.getBlocking(500ms))
we can cleanup the device w/o explicit disconnect command.
+++
The usual disconnect signal from a device forced shutdown is as follows:
L2CAP send or GATT read-reply -> Device -> HCI(1) + Mgmt(2)
(1) HCI disconnect skipped if IO-Error
(2) Mgmt disconnect skipped if IO-Error, but sends DISCONNECT event
+++
Mgmt and GATTHandler also differentiate timeouts,
lenghthly 3s for the ringbuffer read w/o any impact and 1s (mgmt) or 500ms (gatt) for command replies
on the user thread.
This leads to fast DISCONNECT events for the user and actual device cleanup.
Subsequent connection works w/o issues.
If using HCI connect via discovery (not whitelist),
the turnaround time from forced disconnect to next connect is below 1s.
However, using whitelist, the subsequent connect after the forced disconnect
consumes 'a few seconds' and hence is seemingly not suitable for a responsive system (???).
The latter is true with or without Mgmt disconnect attempts!
Misc:
- L2CAPComm disconnect: Show potention pthread_kill error
- HCIComm send_req/send: Refine ERR_PRINT, remove unsused case HCI_EV_REMOTE_NAME
---
api/direct_bt/DBTAdapter.hpp | 2 +-
api/direct_bt/DBTDevice.hpp | 12 ++++++++----
api/direct_bt/DBTManager.hpp | 6 +++++-
api/direct_bt/GATTHandler.hpp | 13 ++++++++++---
api/direct_bt/HCIComm.hpp | 1 +
5 files changed, 25 insertions(+), 9 deletions(-)
(limited to 'api')
diff --git a/api/direct_bt/DBTAdapter.hpp b/api/direct_bt/DBTAdapter.hpp
index c55a0bd8..855c79a3 100644
--- a/api/direct_bt/DBTAdapter.hpp
+++ b/api/direct_bt/DBTAdapter.hpp
@@ -167,7 +167,7 @@ namespace direct_bt {
friend std::shared_ptr DBTDevice::getSharedInstance() const;
friend void DBTDevice::releaseSharedInstance() const;
friend std::shared_ptr DBTDevice::getConnectionInfo();
- friend void DBTDevice::disconnect(const bool disconnectManager, const uint8_t reason);
+ friend void DBTDevice::disconnect(const bool sentFromManager, const bool ioErrorCause,const uint8_t reason);
friend uint16_t DBTDevice::connectLE(HCIAddressType peer_mac_type, HCIAddressType own_mac_type,
uint16_t interval, uint16_t window,
uint16_t min_interval, uint16_t max_interval,
diff --git a/api/direct_bt/DBTDevice.hpp b/api/direct_bt/DBTDevice.hpp
index ef524855..2812358c 100644
--- a/api/direct_bt/DBTDevice.hpp
+++ b/api/direct_bt/DBTDevice.hpp
@@ -50,6 +50,7 @@ namespace direct_bt {
class DBTDevice : public DBTObject
{
friend DBTAdapter; // managing us: ctor and update(..) during discovery
+ friend GATTHandler; // may issue detailed disconnect(..)
private:
static const int to_connect_ms = 5000;
@@ -67,7 +68,7 @@ namespace direct_bt {
std::shared_ptr gattGenericAccess = nullptr;
std::recursive_mutex mtx_data;
std::recursive_mutex mtx_gatt;
-
+ std::atomic isConnected;
DBTDevice(DBTAdapter & adapter, EInfoReport const & r);
bool addService(std::shared_ptr const &uuid);
@@ -81,7 +82,10 @@ namespace direct_bt {
void releaseSharedInstance() const;
void notifyDisconnected();
- void disconnect(const bool disconnectManager, const uint8_t reason=0x13 /* HCIErrorCode::REMOTE_USER_TERMINATED_CONNECTION */);
+ void notifyConnected();
+
+ void disconnect(const bool sentFromManager, const bool ioErrorCause,
+ const uint8_t reason=0x13 /* HCIErrorCode::REMOTE_USER_TERMINATED_CONNECTION */);
public:
const uint64_t ts_creation;
@@ -222,7 +226,7 @@ namespace direct_bt {
*
*/
void disconnect(const uint8_t reason=0x13 /* HCIErrorCode::REMOTE_USER_TERMINATED_CONNECTION */) {
- disconnect(true /* disconnectManager */, reason);
+ disconnect(false /* sentFromManager */, false /* ioErrorCause */, reason);
}
/**
@@ -251,7 +255,7 @@ namespace direct_bt {
* May return nullptr if not connected or failure.
*
*/
- std::shared_ptr connectGATT(int timeoutMS=GATTHandler::Defaults::L2CAP_READER_THREAD_POLL_TIMEOUT);
+ std::shared_ptr connectGATT(int replyTimeoutMS=GATTHandler::Defaults::L2CAP_COMMAND_REPLY_TIMEOUT);
/** Returns already opened GATTHandler, see connectGATT(..) and disconnectGATT(). */
std::shared_ptr getGATTHandler();
diff --git a/api/direct_bt/DBTManager.hpp b/api/direct_bt/DBTManager.hpp
index 8529cf85..53402ab4 100644
--- a/api/direct_bt/DBTManager.hpp
+++ b/api/direct_bt/DBTManager.hpp
@@ -106,6 +106,8 @@ namespace direct_bt {
/** 3s poll timeout for mgmt reader thread */
MGMT_READER_THREAD_POLL_TIMEOUT = 3000,
+ /** 1s timeout for mgmt command replies */
+ MGMT_COMMAND_REPLY_TIMEOUT = 1000,
MGMTEVT_RING_CAPACITY = 256
};
@@ -280,7 +282,9 @@ namespace direct_bt {
const uint16_t min_ce_length=0x0001, const uint16_t max_ce_length=0x0001,
const uint8_t initiator_filter=0);
- bool disconnect(const int dev_id, const EUI48 &peer_bdaddr, const BDAddressType peer_mac_type, const uint8_t reason=0);
+ bool disconnect(const bool ioErrorCause,
+ const int dev_id, const EUI48 &peer_bdaddr, const BDAddressType peer_mac_type,
+ const uint8_t reason=0x13 /* HCIErrorCode::REMOTE_USER_TERMINATED_CONNECTION */);
std::shared_ptr getConnectionInfo(const int dev_id, const EUI48 &address, const BDAddressType address_type);
std::shared_ptr setLocalName(const int dev_id, const std::string & name, const std::string & short_name);
diff --git a/api/direct_bt/GATTHandler.hpp b/api/direct_bt/GATTHandler.hpp
index bc77abab..30f7f0d7 100644
--- a/api/direct_bt/GATTHandler.hpp
+++ b/api/direct_bt/GATTHandler.hpp
@@ -85,6 +85,9 @@ namespace direct_bt {
/** 3s poll timeout for l2cap reader thread */
L2CAP_READER_THREAD_POLL_TIMEOUT = 3000,
+ /** 500ms timeout for l2cap command replies */
+ L2CAP_COMMAND_REPLY_TIMEOUT = 500,
+
ATTPDU_RING_CAPACITY = 256
};
@@ -97,7 +100,7 @@ namespace direct_bt {
POctets rbuffer;
L2CAPComm l2cap;
- const int timeoutMS;
+ const int replyTimeoutMS;
std::atomic state;
LFRingbuffer, nullptr> attPDURing;
@@ -130,8 +133,10 @@ namespace direct_bt {
*/
uint16_t exchangeMTU(const uint16_t clientMaxMTU=ClientMaxMTU);
+ bool disconnect(const bool ioErrorCause);
+
public:
- GATTHandler(const std::shared_ptr & device, const int timeoutMS = Defaults::L2CAP_READER_THREAD_POLL_TIMEOUT);
+ GATTHandler(const std::shared_ptr & device, const int replyTimeoutMS = Defaults::L2CAP_COMMAND_REPLY_TIMEOUT);
~GATTHandler();
@@ -143,7 +148,9 @@ namespace direct_bt {
* See getServerMTU() and getUsedMTU(), the latter is in use.
*/
bool connect();
- bool disconnect();
+ bool disconnect() {
+ return disconnect(false /* ioErrorCause */);
+ }
bool isOpen() const { return Disconnected < state && l2cap.isOpen(); }
uint16_t getServerMTU() const { return serverMTU; }
diff --git a/api/direct_bt/HCIComm.hpp b/api/direct_bt/HCIComm.hpp
index 695aab09..2e7566f1 100644
--- a/api/direct_bt/HCIComm.hpp
+++ b/api/direct_bt/HCIComm.hpp
@@ -46,6 +46,7 @@
namespace direct_bt {
enum HCIDefaults : int {
+ /** 3s poll timeout for HCI readout */
HCI_TO_SEND_REQ_POLL_MS = 3000
};
--
cgit v1.2.3