diff options
author | Sven Gothel <[email protected]> | 2020-05-11 10:22:39 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-05-11 10:22:39 +0200 |
commit | b06528b908c43860ebd89f72d5f5675ac82badea (patch) | |
tree | cce1c7a079c9ef3e7f185afa23c0633113052808 /src | |
parent | 2a264bce0f6e5fffdc9488c5e00babd22d711876 (diff) |
Resolving flushed discovered devices and shared device reference usage.
Commit 09cd1183b3599357b05c426e2b59e8df813304c5 describes existed issue
in a multi device and hence multi-device-discovery environment.
(The change has been reverted)
This changed resolves the shared device reference usage,
by having adapter maintaining a 'sharedDevices' list
in parallel to the 'discoveredDevices'.
Adapter will add a newly found and created device
to both lists, shared- and discovered devices.
Device may remove itself from the sharedDevices list
via remove() and its destructor.
Adapter will also look in sharedDevices in connected and found
callback to determine if a device is known and re-adds it
to the discovered devices list for consistency.
(Note: discoveredDevices may be flushed via a new startDiscovery)
Diffstat (limited to 'src')
-rw-r--r-- | src/direct_bt/DBTAdapter.cpp | 115 | ||||
-rw-r--r-- | src/direct_bt/DBTDevice.cpp | 91 |
2 files changed, 154 insertions, 52 deletions
diff --git a/src/direct_bt/DBTAdapter.cpp b/src/direct_bt/DBTAdapter.cpp index 0005690b..7b542051 100644 --- a/src/direct_bt/DBTAdapter.cpp +++ b/src/direct_bt/DBTAdapter.cpp @@ -62,28 +62,27 @@ HCISession::HCISession(DBTAdapter &a, const uint16_t channel, const int timeoutM name(name_counter.fetch_add(1)) {} -bool HCISession::connected(std::shared_ptr<DBTDevice> & device) { +void HCISession::connected(const std::shared_ptr<DBTDevice> & device) { const std::lock_guard<std::recursive_mutex> lock(mtx_connectedDevices); // RAII-style acquire and relinquish via destructor for (auto it = connectedDevices.begin(); it != connectedDevices.end(); ++it) { if ( *device == **it ) { - return false; // already connected + throw InternalError("Device already connected: "+device->toString(), E_FILE_LINE); } } connectedDevices.push_back(device); - return true; } -bool HCISession::disconnected(std::shared_ptr<DBTDevice> & device) { +void HCISession::disconnected(const DBTDevice & device) { const std::lock_guard<std::recursive_mutex> lock(mtx_connectedDevices); // RAII-style acquire and relinquish via destructor for (auto it = connectedDevices.begin(); it != connectedDevices.end(); ) { - if ( **it == *device ) { + if ( &device == (*it).get() ) { // compare actual device address it = connectedDevices.erase(it); - return true; + return; } else { ++it; } } - return false; + throw InternalError("Device not connected: "+device.toString(), E_FILE_LINE); } int HCISession::disconnectAllDevices(const uint8_t reason) { @@ -214,13 +213,14 @@ DBTAdapter::~DBTAdapter() { } statusListenerList.clear(); - removeDiscoveredDevices(); - if( nullptr != session ) { stopDiscovery(); session->shutdown(); // force shutdown, not only via dtor as adapter EOL has been reached! session = nullptr; } + removeDiscoveredDevices(); + sharedDevices.clear(); + DBG_PRINT("DBTAdapter::dtor: XXX"); } @@ -379,6 +379,51 @@ std::vector<std::shared_ptr<DBTDevice>> DBTAdapter::getDiscoveredDevices() const return res; } +bool DBTAdapter::addSharedDevice(std::shared_ptr<DBTDevice> const &device) { + const std::lock_guard<std::recursive_mutex> lock(mtx_sharedDevices); // RAII-style acquire and relinquish via destructor + for (auto it = sharedDevices.begin(); it != sharedDevices.end(); ++it) { + if ( *device == **it ) { + // already shared + return false; + } + } + sharedDevices.push_back(device); + return true; +} + +std::shared_ptr<DBTDevice> DBTAdapter::getSharedDevice(const DBTDevice & device) { + const std::lock_guard<std::recursive_mutex> lock(mtx_sharedDevices); // RAII-style acquire and relinquish via destructor + for (auto it = sharedDevices.begin(); it != sharedDevices.end(); ++it) { + if ( &device == (*it).get() ) { // compare actual device address + return *it; // done + } + } + return nullptr; +} + +void DBTAdapter::releaseSharedDevice(const DBTDevice & device) { + const std::lock_guard<std::recursive_mutex> lock(mtx_sharedDevices); // RAII-style acquire and relinquish via destructor + for (auto it = sharedDevices.begin(); it != sharedDevices.end(); ++it) { + if ( &device == (*it).get() ) { // compare actual device address + sharedDevices.erase(it); + return; // unique set + } + } +} + +std::shared_ptr<DBTDevice> DBTAdapter::findSharedDevice (EUI48 const & mac) const { + const std::lock_guard<std::recursive_mutex> lock(const_cast<DBTAdapter*>(this)->mtx_sharedDevices); // RAII-style acquire and relinquish via destructor + auto begin = sharedDevices.begin(); + auto it = std::find_if(begin, sharedDevices.end(), [&](std::shared_ptr<DBTDevice> const& p) { + return p->address == mac; + }); + if ( it == std::end(sharedDevices) ) { + return nullptr; + } else { + return *it; + } +} + std::string DBTAdapter::toString() const { std::string out("Adapter["+getAddressString()+", '"+getName()+"', id="+std::to_string(dev_id)+", "+javaObjectToString()+"]"); std::vector<std::shared_ptr<DBTDevice>> devices = getDiscoveredDevices(); @@ -462,17 +507,24 @@ bool DBTAdapter::mgmtEvDeviceConnectedCB(std::shared_ptr<MgmtEvent> e) { ad_report.setAddress( event.getAddress() ); ad_report.read_data(event.getData(), event.getDataSize()); } - bool new_connect = false; + int new_connect = 0; std::shared_ptr<DBTDevice> device = session->findConnectedDevice(event.getAddress()); if( nullptr == device ) { device = findDiscoveredDevice(event.getAddress()); - new_connect = true; + new_connect = nullptr != device ? 1 : 0; + } + if( nullptr == device ) { + device = findSharedDevice(event.getAddress()); + if( nullptr != device ) { + addDiscoveredDevice(device); + new_connect = 2; + } } if( nullptr != device ) { EIRDataType updateMask = device->update(ad_report); DBG_PRINT("DBTAdapter::EventCB:DeviceConnected(dev_id %d, new_connect %d, updated %s): %s,\n %s\n -> %s", dev_id, new_connect, eirDataMaskToString(updateMask).c_str(), event.toString().c_str(), ad_report.toString().c_str(), device->toString().c_str()); - if( new_connect ) { + if( 0 < new_connect ) { session->connected(device); // track it } for_each_idx_mtx(mtx_statusListenerList, statusListenerList, [&](std::shared_ptr<DBTAdapterStatusListener> &l) { @@ -521,21 +573,40 @@ bool DBTAdapter::mgmtEvDeviceFoundCB(std::shared_ptr<MgmtEvent> e) { ad_report.read_data(deviceFoundEvent.getData(), deviceFoundEvent.getDataSize()); std::shared_ptr<DBTDevice> dev = findDiscoveredDevice(ad_report.getAddress()); - if( nullptr == dev ) { - // new device - dev = std::shared_ptr<DBTDevice>(new DBTDevice(*this, ad_report)); - addDiscoveredDevice(dev); - - for_each_idx_mtx(mtx_statusListenerList, statusListenerList, [&](std::shared_ptr<DBTAdapterStatusListener> &l) { - l->deviceFound(*this, dev, ad_report.getTimestamp()); - }); - - } else { + if( nullptr != dev ) { + // // existing device + // + EIRDataType updateMask = dev->update(ad_report); + if( EIRDataType::NONE != updateMask ) { + sendDeviceUpdated(dev, ad_report.getTimestamp(), updateMask); + } + return true; + } + + dev = findSharedDevice(ad_report.getAddress()); + if( nullptr != dev ) { + // + // active shared device, but flushed from discovered devices + // + addDiscoveredDevice(dev); // re-add to discovered devices! EIRDataType updateMask = dev->update(ad_report); if( EIRDataType::NONE != updateMask ) { sendDeviceUpdated(dev, ad_report.getTimestamp(), updateMask); } + return true; } + + // + // new device + // + dev = std::shared_ptr<DBTDevice>(new DBTDevice(*this, ad_report)); + addDiscoveredDevice(dev); + addSharedDevice(dev); + + for_each_idx_mtx(mtx_statusListenerList, statusListenerList, [&](std::shared_ptr<DBTAdapterStatusListener> &l) { + l->deviceFound(*this, dev, ad_report.getTimestamp()); + }); + return true; } diff --git a/src/direct_bt/DBTDevice.cpp b/src/direct_bt/DBTDevice.cpp index 01e232f9..983e97b8 100644 --- a/src/direct_bt/DBTDevice.cpp +++ b/src/direct_bt/DBTDevice.cpp @@ -55,17 +55,16 @@ DBTDevice::DBTDevice(DBTAdapter & a, EInfoReport const & r) } DBTDevice::~DBTDevice() { - disconnect(); + remove(); services.clear(); msd = nullptr; } std::shared_ptr<DBTDevice> DBTDevice::getSharedInstance() const { - const std::shared_ptr<DBTDevice> myself = adapter.findDiscoveredDevice(address); - if( nullptr == myself ) { - throw InternalError("DBTDevice: Not present in DBTAdapter: "+toString(), E_FILE_LINE); - } - return myself; + return adapter.getSharedDevice(*this); +} +void DBTDevice::releaseSharedInstance() const { + adapter.releaseSharedDevice(*this); } bool DBTDevice::addService(std::shared_ptr<uuid_t> const &uuid) @@ -190,7 +189,12 @@ std::shared_ptr<ConnectionInfo> DBTDevice::getConnectionInfo() { setEIRDataTypeSet(updateMask, EIRDataType::TX_POWER); } if( EIRDataType::NONE != updateMask ) { - adapter.sendDeviceUpdated(getSharedInstance(), getCurrentMilliseconds(), updateMask); + std::shared_ptr<DBTDevice> sharedInstance = getSharedInstance(); + if( nullptr == sharedInstance ) { + ERR_PRINT("DBTDevice::getConnectionInfo: Device unknown to adapter and not tracked: %s", toString().c_str()); + } else { + adapter.sendDeviceUpdated(sharedInstance, getCurrentMilliseconds(), updateMask); + } } } return connInfo; @@ -203,17 +207,23 @@ uint16_t DBTDevice::le_connect(HCIAddressType peer_mac_type, HCIAddressType own_ uint16_t min_ce_length, uint16_t max_ce_length, uint8_t initiator_filter ) { + std::shared_ptr<DBTDevice> sharedInstance = getSharedInstance(); + if( nullptr == sharedInstance ) { + ERR_PRINT("DBTDevice::le_connect: Device unknown to adapter and not tracked: %s", toString().c_str()); + return 0; + } if( 0 < connHandle ) { ERR_PRINT("DBTDevice::le_connect: Already connected"); return 0; } if( !isLEAddressType() ) { - ERR_PRINT("DBTDevice::connect: Not a BDADDR_LE_PUBLIC or BDADDR_LE_RANDOM address: %s", toString().c_str()); + ERR_PRINT("DBTDevice::le_connect: Not a BDADDR_LE_PUBLIC or BDADDR_LE_RANDOM address: %s", toString().c_str()); + return 0; } std::shared_ptr<HCISession> session = adapter.getOpenSession(); if( nullptr == session || !session->isOpen() ) { - ERR_PRINT("DBTDevice::le_connect: Not opened"); + ERR_PRINT("DBTDevice::le_connect: Adapter session not opened"); return 0; } @@ -232,14 +242,18 @@ uint16_t DBTDevice::le_connect(HCIAddressType peer_mac_type, HCIAddressType own_ ERR_PRINT("DBTDevice::le_connect: Could not create connection"); return 0; } - std::shared_ptr<DBTDevice> thisDevice = getSharedInstance(); - session->connected(thisDevice); + session->connected(sharedInstance); return connHandle; } uint16_t DBTDevice::connect(const uint16_t pkt_type, const uint16_t clock_offset, const uint8_t role_switch) { + std::shared_ptr<DBTDevice> sharedInstance = getSharedInstance(); + if( nullptr == sharedInstance ) { + ERR_PRINT("DBTDevice::connect: Device unknown to adapter and not tracked: %s", toString().c_str()); + return 0; + } if( 0 < connHandle ) { ERR_PRINT("DBTDevice::connect: Already connected"); return 0; @@ -247,11 +261,12 @@ uint16_t DBTDevice::connect(const uint16_t pkt_type, const uint16_t clock_offset if( !isBREDRAddressType() ) { ERR_PRINT("DBTDevice::connect: Not a BDADDR_BREDR address: %s", toString().c_str()); + return 0; } std::shared_ptr<HCISession> session = adapter.getOpenSession(); if( nullptr == session || !session->isOpen() ) { - ERR_PRINT("DBTDevice::connect: Not opened"); + ERR_PRINT("DBTDevice::connect: Adapter session Not opened"); return 0; } @@ -264,11 +279,10 @@ uint16_t DBTDevice::connect(const uint16_t pkt_type, const uint16_t clock_offset connHandle = session->hciComm.create_conn(address, pkt_type, clock_offset, role_switch); if ( 0 == connHandle ) { - ERR_PRINT("DBTDevice::connect: Could not create connection"); + ERR_PRINT("DBTDevice::connect: Could not create connection (yet)"); return 0; } - std::shared_ptr<DBTDevice> thisDevice = getSharedInstance(); - session->connected(thisDevice); + session->connected(sharedInstance); return connHandle; } @@ -291,21 +305,24 @@ uint16_t DBTDevice::defaultConnect() void DBTDevice::disconnect(const uint8_t reason) { disconnectGATT(); + std::shared_ptr<HCISession> session = adapter.getOpenSession(); + if( 0 == connHandle ) { DBG_PRINT("DBTDevice::disconnect: Not connected"); - return; + goto errout; } - std::shared_ptr<HCISession> session = adapter.getOpenSession(); if( nullptr == session || !session->isOpen() ) { DBG_PRINT("DBTDevice::disconnect: Session not opened"); - return; + goto errout; } - const uint16_t _connHandle = connHandle; - connHandle = 0; - if( !session->hciComm.disconnect(_connHandle, reason) ) { - DBG_PRINT("DBTDevice::disconnect: handle 0x%X, errno %d %s", _leConnHandle, errno, strerror(errno)); + { + const uint16_t _connHandle = connHandle; + connHandle = 0; + if( !session->hciComm.disconnect(_connHandle, reason) ) { + DBG_PRINT("DBTDevice::disconnect: handle 0x%X, errno %d %s", _leConnHandle, errno, strerror(errno)); + } } { @@ -313,26 +330,40 @@ void DBTDevice::disconnect(const uint8_t reason) { DBTManager & mngr = adapter.getManager(); mngr.disconnect(adapter.dev_id, address, addressType, reason); } + session->disconnected(*this); + return; + +errout: + if( nullptr != session ) { + session->disconnected(*this); + } +} - std::shared_ptr<DBTDevice> thisDevice = getSharedInstance(); - session->disconnected(thisDevice); +void DBTDevice::remove() { + disconnect(0); + releaseSharedInstance(); } std::shared_ptr<GATTHandler> DBTDevice::connectGATT(int timeoutMS) { - if( 0 == connHandle ) { - DBG_PRINT("DBTDevice::connectGATT: Not connected"); - return nullptr; - } std::shared_ptr<HCISession> session = adapter.getOpenSession(); if( nullptr == session || !session->isOpen() ) { - DBG_PRINT("DBTDevice::connectGATT: Session not opened"); + DBG_PRINT("DBTDevice::connectGATT: Adapter session not opened"); + return nullptr; + } + if( 0 == connHandle ) { + DBG_PRINT("DBTDevice::connectGATT: Device not connected"); return nullptr; } + std::shared_ptr<DBTDevice> sharedInstance = getSharedInstance(); + if( nullptr == sharedInstance ) { + throw InternalError("DBTDevice::connectGATT: Device unknown to adapter and not tracked: "+toString(), E_FILE_LINE); + } + const std::lock_guard<std::recursive_mutex> lock(mtx_gatt); // RAII-style acquire and relinquish via destructor if( nullptr != gattHandler ) { return gattHandler; } - std::shared_ptr<GATTHandler> _gattHandler = std::shared_ptr<GATTHandler>(new GATTHandler(this->getSharedInstance(), timeoutMS)); + std::shared_ptr<GATTHandler> _gattHandler = std::shared_ptr<GATTHandler>(new GATTHandler(sharedInstance, timeoutMS)); if( _gattHandler->connect() ) { gattHandler = _gattHandler; } else { |