Skip to content

Commit 4746c60

Browse files
committed
[Bugfix] Incorrect Client connection state tracking and self delete
This adds better client state tracking so that functions like NimBLEDevice::getDisconnectedClient get a more accurate state and will not return a connecting client. This also fixes the client self delete on connection error where function call errors did not delete the client
1 parent 9abb7dd commit 4746c60

3 files changed

Lines changed: 58 additions & 51 deletions

File tree

src/NimBLEClient.cpp

Lines changed: 43 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ NimBLEClient::NimBLEClient(const NimBLEAddress& peerAddress)
6868
m_terminateFailCount{0},
6969
m_asyncSecureAttempt{0},
7070
m_config{},
71+
m_connStatus{DISCONNECTED},
7172
# if MYNEWT_VAL(BLE_EXT_ADV)
7273
m_phyMask{BLE_GAP_LE_PHY_1M_MASK | BLE_GAP_LE_PHY_2M_MASK | BLE_GAP_LE_PHY_CODED_MASK},
7374
# endif
@@ -171,35 +172,30 @@ bool NimBLEClient::connect(bool deleteAttributes, bool asyncConnect, bool exchan
171172
*/
172173
bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes, bool asyncConnect, bool exchangeMTU) {
173174
NIMBLE_LOGD(LOG_TAG, ">> connect(%s)", address.toString().c_str());
175+
NimBLETaskData taskData(this);
176+
const ble_addr_t* peerAddr = address.getBase();
177+
int rc = 0;
174178

175179
if (!NimBLEDevice::m_synced) {
176-
NIMBLE_LOGE(LOG_TAG, "Host reset, wait for sync.");
177-
return false;
180+
NIMBLE_LOGE(LOG_TAG, "Host not synced with controller.");
181+
rc = BLE_HS_ENOTSYNCED;
182+
goto error;
178183
}
179184

180-
if (isConnected()) {
181-
NIMBLE_LOGE(LOG_TAG, "Client already connected");
182-
return false;
183-
}
184-
185-
const ble_addr_t* peerAddr = address.getBase();
186-
if (ble_gap_conn_find_by_addr(peerAddr, NULL) == 0) {
187-
NIMBLE_LOGE(LOG_TAG, "A connection to %s already exists", address.toString().c_str());
188-
return false;
185+
if (m_connStatus != DISCONNECTED) {
186+
NIMBLE_LOGE(LOG_TAG, "Client not disconnected, cannot connect");
187+
rc = BLE_HS_EREJECT;
188+
goto error;
189189
}
190190

191191
if (address.isNull()) {
192192
NIMBLE_LOGE(LOG_TAG, "Invalid peer address; (NULL)");
193-
return false;
194-
} else {
195-
m_peerAddress = address;
193+
rc = BLE_HS_EINVAL;
194+
goto error;
196195
}
197196

198-
if (deleteAttributes) {
199-
deleteServices();
200-
}
201-
202-
int rc = 0;
197+
m_connStatus = CONNECTING;
198+
m_peerAddress = address;
203199
m_config.asyncConnect = asyncConnect;
204200
m_config.exchangeMTU = exchangeMTU;
205201

@@ -259,22 +255,24 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes,
259255

260256
} while (rc == BLE_HS_EBUSY);
261257

258+
if (deleteAttributes) {
259+
deleteServices();
260+
}
261+
262262
if (rc != 0) {
263-
m_lastErr = rc;
264-
return false;
263+
goto error;
265264
}
266265

267266
if (m_config.asyncConnect) {
268267
return true;
269268
}
270269

271-
NimBLETaskData taskData(this);
272270
m_pTaskData = &taskData;
273271

274272
// Wait for the connect timeout time +1 second for the connection to complete
275273
if (!NimBLEUtils::taskWait(taskData, m_connectTimeout + 1000)) {
276274
// If a connection was made but no response from MTU exchange proceed anyway
277-
if (isConnected()) {
275+
if (m_connStatus == CONNECTED && m_config.exchangeMTU) {
278276
taskData.m_flags = 0;
279277
} else {
280278
// workaround; if the controller doesn't cancel the connection at the timeout, cancel it here.
@@ -288,17 +286,20 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes,
288286
rc = taskData.m_flags;
289287
if (rc != 0) {
290288
NIMBLE_LOGE(LOG_TAG, "Connection failed; status=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
291-
m_lastErr = rc;
292-
if (m_config.deleteOnConnectFail) {
293-
NimBLEDevice::deleteClient(this);
294-
}
295-
return false;
289+
goto error;
296290
}
297291

298292
m_pClientCallbacks->onConnect(this);
299293
NIMBLE_LOGD(LOG_TAG, "<< connect()");
300-
// Check if still connected before returning
301-
return isConnected();
294+
return true;
295+
296+
error:
297+
m_connStatus = DISCONNECTED;
298+
m_lastErr = rc;
299+
if (m_config.deleteOnConnectFail) {
300+
NimBLEDevice::deleteClient(this);
301+
}
302+
return false;
302303
} // connect
303304

304305
/**
@@ -358,6 +359,7 @@ bool NimBLEClient::disconnect(uint8_t reason) {
358359
return false;
359360
}
360361

362+
m_connStatus = (rc == BLE_HS_ENOTCONN) ? DISCONNECTED : DISCONNECTING;
361363
return true;
362364
} // disconnect
363365

@@ -575,8 +577,8 @@ NimBLEAddress NimBLEClient::getPeerAddress() const {
575577
* @return True if successful.
576578
*/
577579
bool NimBLEClient::setPeerAddress(const NimBLEAddress& address) {
578-
if (isConnected()) {
579-
NIMBLE_LOGE(LOG_TAG, "Cannot set peer address while connected");
580+
if (m_connStatus == CONNECTED || m_connStatus == CONNECTING) {
581+
NIMBLE_LOGE(LOG_TAG, "Cannot set peer address while connected/connecting");
580582
return false;
581583
}
582584

@@ -589,7 +591,7 @@ bool NimBLEClient::setPeerAddress(const NimBLEAddress& address) {
589591
* @return The RSSI value or 0 if there was an error.
590592
*/
591593
int NimBLEClient::getRssi() const {
592-
if (!isConnected()) {
594+
if (m_connStatus != CONNECTED) {
593595
NIMBLE_LOGE(LOG_TAG, "getRssi(): Not connected");
594596
return 0;
595597
}
@@ -732,7 +734,7 @@ bool NimBLEClient::discoverAttributes() {
732734
* @return true on success otherwise false if an error occurred
733735
*/
734736
bool NimBLEClient::retrieveServices(const NimBLEUUID* uuidFilter) {
735-
if (!isConnected()) {
737+
if (m_connStatus != CONNECTED) {
736738
NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve services -aborting");
737739
return false;
738740
}
@@ -968,6 +970,7 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
968970

969971
pClient->m_terminateFailCount = 0;
970972
pClient->m_asyncSecureAttempt = 0;
973+
pClient->m_connStatus = DISCONNECTED;
971974

972975
// Don't call the disconnect callback if we are waiting for a connection to complete and it fails
973976
if (rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_CONN_ESTABLISHMENT) && pClient->m_config.asyncConnect) {
@@ -994,7 +997,8 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
994997

995998
case BLE_GAP_EVENT_CONNECT: {
996999
// If we aren't waiting for this connection response we should drop the connection immediately.
997-
if (pClient->isConnected() || (!pClient->m_config.asyncConnect && pClient->m_pTaskData == nullptr)) {
1000+
if (pClient->m_connStatus != CONNECTING ||
1001+
(!pClient->m_config.asyncConnect && pClient->m_pTaskData == nullptr)) {
9981002
ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM);
9991003
return 0;
10001004
}
@@ -1005,6 +1009,7 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
10051009
}
10061010

10071011
if (rc == 0) {
1012+
pClient->m_connStatus = CONNECTED;
10081013
pClient->m_connHandle = event->connect.conn_handle;
10091014

10101015
if (pClient->m_config.asyncConnect) {
@@ -1013,13 +1018,13 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
10131018

10141019
if (pClient->m_config.exchangeMTU) {
10151020
if (!pClient->exchangeMTU()) {
1016-
rc = pClient->m_lastErr; // sets the error in the task data
1017-
break;
1021+
break; // if exchangeMTU fails we will just continue, likely will disconnect immediately after
10181022
}
10191023

10201024
return 0; // return as we may have a task waiting for the MTU before releasing it.
10211025
}
10221026
} else {
1027+
pClient->m_connStatus = DISCONNECTED;
10231028
pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
10241029

10251030
if (pClient->m_config.asyncConnect) {
@@ -1258,7 +1263,7 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
12581263
* @return True if we are connected and false if we are not connected.
12591264
*/
12601265
bool NimBLEClient::isConnected() const {
1261-
return m_connHandle != BLE_HS_CONN_HANDLE_NONE;
1266+
return m_connStatus == CONNECTED;
12621267
} // isConnected
12631268

12641269
/**
@@ -1348,6 +1353,5 @@ void NimBLEClientCallbacks::onMTUChange(NimBLEClient* pClient, uint16_t mtu) {
13481353
void NimBLEClientCallbacks::onPhyUpdate(NimBLEClient* pClient, uint8_t txPhy, uint8_t rxPhy) {
13491354
NIMBLE_LOGD(CB_TAG, "onPhyUpdate: default, txPhy: %d, rxPhy: %d", txPhy, rxPhy);
13501355
} // onPhyUpdate
1351-
#
13521356

13531357
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_CENTRAL)

src/NimBLEClient.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ class NimBLEClient {
113113
void setConfig(Config config);
114114

115115
private:
116+
enum ConnStatus : uint8_t { CONNECTED, DISCONNECTED, CONNECTING, DISCONNECTING };
117+
116118
NimBLEClient(const NimBLEAddress& peerAddress);
117119
~NimBLEClient();
118120
NimBLEClient(const NimBLEClient&) = delete;
@@ -136,6 +138,7 @@ class NimBLEClient {
136138
uint8_t m_terminateFailCount;
137139
mutable uint8_t m_asyncSecureAttempt;
138140
Config m_config;
141+
ConnStatus m_connStatus;
139142

140143
# if MYNEWT_VAL(BLE_EXT_ADV)
141144
uint8_t m_phyMask;

src/NimBLEDevice.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -362,12 +362,12 @@ bool NimBLEDevice::deleteClient(NimBLEClient* pClient) {
362362

363363
for (auto& clt : m_pClients) {
364364
if (clt == pClient) {
365-
if (clt->isConnected()) {
365+
if (clt->m_connStatus == NimBLEClient::CONNECTED || clt->m_connStatus == NimBLEClient::DISCONNECTING) {
366366
clt->m_config.deleteOnDisconnect = true;
367367
if (!clt->disconnect()) {
368368
break;
369369
}
370-
} else if (pClient->m_pTaskData != nullptr) {
370+
} else if (pClient->m_connStatus == NimBLEClient::CONNECTING) {
371371
clt->m_config.deleteOnConnectFail = true;
372372
if (!clt->cancelConnect()) {
373373
break;
@@ -435,7 +435,7 @@ NimBLEClient* NimBLEDevice::getClientByPeerAddress(const NimBLEAddress& addr) {
435435
*/
436436
NimBLEClient* NimBLEDevice::getDisconnectedClient() {
437437
for (const auto clt : m_pClients) {
438-
if (clt != nullptr && !clt->isConnected()) {
438+
if (clt != nullptr && clt->m_connStatus == NimBLEClient::DISCONNECTED) {
439439
return clt;
440440
}
441441
}
@@ -685,7 +685,7 @@ bool NimBLEDevice::isBonded(const NimBLEAddress& address) {
685685
* @returns NimBLEAddress of the found bonded peer or null address if not found.
686686
*/
687687
NimBLEAddress NimBLEDevice::getBondedAddress(int index) {
688-
# if MYNEWT_VAL(BLE_STORE_MAX_BONDS)
688+
# if MYNEWT_VAL(BLE_STORE_MAX_BONDS)
689689
ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
690690
int num_peers, rc;
691691
rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS));
@@ -694,10 +694,10 @@ NimBLEAddress NimBLEDevice::getBondedAddress(int index) {
694694
}
695695

696696
return NimBLEAddress(peer_id_addrs[index]);
697-
# else
697+
# else
698698
(void)index; // unused
699699
return NimBLEAddress{};
700-
# endif
700+
# endif
701701
}
702702
# endif
703703

@@ -1278,17 +1278,17 @@ bool NimBLEDevice::startSecurity(uint16_t connHandle, int* rcPtr) {
12781278
* @return true if the passkey was injected successfully.
12791279
*/
12801280
bool NimBLEDevice::injectPassKey(const NimBLEConnInfo& peerInfo, uint32_t passkey) {
1281-
#if MYNEWT_VAL(BLE_SM_LEGACY)
1281+
# if MYNEWT_VAL(BLE_SM_LEGACY)
12821282
ble_sm_io pkey{.action = BLE_SM_IOACT_INPUT, .passkey = passkey};
12831283
int rc = ble_sm_inject_io(peerInfo.getConnHandle(), &pkey);
12841284
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_INPUT; ble_sm_inject_io result: %d", rc);
12851285
return rc == 0;
1286-
#else
1286+
# else
12871287
(void)peerInfo;
12881288
(void)passkey;
12891289
NIMBLE_LOGE(LOG_TAG, "Passkey entry not supported with current security settings");
12901290
return false;
1291-
#endif
1291+
# endif
12921292
}
12931293

12941294
/**
@@ -1297,17 +1297,17 @@ bool NimBLEDevice::injectPassKey(const NimBLEConnInfo& peerInfo, uint32_t passke
12971297
* @param [in] accept Whether the user confirmed or declined the comparison.
12981298
*/
12991299
bool NimBLEDevice::injectConfirmPasskey(const NimBLEConnInfo& peerInfo, bool accept) {
1300-
#if MYNEWT_VAL(BLE_SM_SC)
1300+
# if MYNEWT_VAL(BLE_SM_SC)
13011301
ble_sm_io pkey{.action = BLE_SM_IOACT_NUMCMP, .numcmp_accept = accept};
13021302
int rc = ble_sm_inject_io(peerInfo.getConnHandle(), &pkey);
13031303
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_NUMCMP; ble_sm_inject_io result: %d", rc);
13041304
return rc == 0;
1305-
#else
1305+
# else
13061306
(void)peerInfo;
13071307
(void)accept;
13081308
NIMBLE_LOGE(LOG_TAG, "Numeric comparison not supported with current security settings");
13091309
return false;
1310-
#endif
1310+
# endif
13111311
}
13121312
# endif // MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
13131313

0 commit comments

Comments
 (0)