From 32e7ca2d2d387d74eaeac09751049778faea4040 Mon Sep 17 00:00:00 2001 From: Matthew McGowan Date: Sat, 31 Jan 2026 13:53:57 -0800 Subject: [PATCH] fix(server): notify characteristics on client disconnect When a client disconnects, iterate through all services and characteristics and call processSubRequest with subValue=0 for any that had subscriptions from the disconnecting client. This ensures that application callbacks (onSubscribe) are properly notified when a client disconnects, allowing them to clean up their subscription state. Previously, the onSubscribe callback was only called when the client explicitly unsubscribed by writing to the CCCD, not when the connection was terminated. This fixes issues where: - Subscriber counts would not decrement on disconnect - Blocking reads would hang forever waiting for unsubscribe notification - Applications could not detect client disconnection via characteristic callbacks --- src/NimBLEServer.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/NimBLEServer.cpp b/src/NimBLEServer.cpp index 3c062f78..0283f742 100644 --- a/src/NimBLEServer.cpp +++ b/src/NimBLEServer.cpp @@ -427,11 +427,27 @@ int NimBLEServer::handleGapEvent(ble_gap_event* event, void* arg) { } # endif + // Notify characteristics that the client has unsubscribed. + // This ensures onSubscribe callbacks are called with subValue=0 + // so applications can clean up their subscription state. + peerInfo.m_desc = event->disconnect.conn; + for (const auto& svc : pServer->m_svcVec) { + for (const auto& chr : svc->getCharacteristics()) { + auto subscribers = chr->getSubscribers(); + for (const auto& entry : subscribers) { + if (entry.getConnHandle() == event->disconnect.conn.conn_handle && + (entry.isSubNotify() || entry.isSubIndicate())) { + chr->processSubRequest(peerInfo, 0); + break; + } + } + } + } + if (pServer->m_svcChanged) { pServer->resetGATT(); } - peerInfo.m_desc = event->disconnect.conn; pServer->m_pServerCallbacks->onDisconnect(pServer, peerInfo, event->disconnect.reason); # if !MYNEWT_VAL(BLE_EXT_ADV) if (pServer->m_advertiseOnDisconnect) {