aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2021-07-31 02:25:03 +0200
committerSven Gothel <[email protected]>2021-07-31 02:25:03 +0200
commit5a63c8ccc1a8edf307be49b1cdb6c786898bd2b2 (patch)
treef543d0201853c4aa13ce66a1e44c48f6882aefdb
parent0e2d05a2b7542c4c2865f736ddc7a1272c730f9d (diff)
dbt_scanner10/DBTScanner10: Extract BTDeviceRegistry and BTSecurityRegistry to lib, support full EUI84Sub and name-sub pattern matching
Same naming-schema and functionality C++/Java Due to using EUI48Sub and name-sub pattern matching, we naturally had to drop the hash-set fast-lookup approach. However, looking up device names via pattern-matching is essential to handle device groups, i.e. - specific security settings (level, passkey, ..) - actually accepting them to connect (waitForDevices)
-rw-r--r--api/direct_bt/BTDeviceRegistry.hpp61
-rw-r--r--api/direct_bt/BTSecurityRegistry.hpp103
-rw-r--r--examples/direct_bt_scanner10/dbt_scanner10.cpp296
-rw-r--r--examples/java/DBTScanner10.java183
-rw-r--r--java/org/direct_bt/BTDeviceRegistry.java165
-rw-r--r--java/org/direct_bt/BTSecurityRegistry.java141
-rwxr-xr-xscripts/run-dbt_scanner10.sh14
-rw-r--r--src/direct_bt/BTDeviceRegistry.cpp174
-rw-r--r--src/direct_bt/BTSecurityRegistry.cpp98
-rw-r--r--src/direct_bt/CMakeLists.txt2
10 files changed, 883 insertions, 354 deletions
diff --git a/api/direct_bt/BTDeviceRegistry.hpp b/api/direct_bt/BTDeviceRegistry.hpp
new file mode 100644
index 00000000..a09c5248
--- /dev/null
+++ b/api/direct_bt/BTDeviceRegistry.hpp
@@ -0,0 +1,61 @@
+/*
+ * Author: Sven Gothel <[email protected]>
+ * Copyright (c) 2020 Gothel Software e.K.
+ * Copyright (c) 2020 ZAFENA AB
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef DBT_DEV_ACCOUNTING_HPP_
+#define DBT_DEV_ACCOUNTING_HPP_
+
+#include <string>
+#include <cstdio>
+
+#include <direct_bt/DirectBT.hpp>
+
+namespace direct_bt {
+
+ /**
+ * Application toolkit providing BT device registration of processed and awaited devices.
+ * The latter on a pattern matching basis, i.e. EUI48Sub or name-sub.
+ */
+ namespace BTDeviceRegistry {
+ void addToWaitForDevices(const std::string& addrOrNameSub);
+ bool isWaitingForDevice(const BDAddressAndType &mac, const std::string &name);
+ bool isWaitingForAnyDevice();
+ size_t getWaitForDevicesCount();
+ void printWaitForDevices(FILE *out, const std::string &msg);
+
+ void addToDevicesProcessed(const BDAddressAndType &a, const std::string& n);
+ bool isDeviceProcessed(const BDAddressAndType & a);
+ size_t getDeviceProcessedCount();
+ bool allDevicesProcessed();
+ void printDevicesProcessed(FILE *out, const std::string &msg);
+
+ void addToDevicesProcessing(const BDAddressAndType &a, const std::string& n);
+ bool removeFromDevicesProcessing(const BDAddressAndType &a);
+ bool isDeviceProcessing(const BDAddressAndType & a);
+ size_t getDeviceProcessingCount();
+ }
+
+} // namespace direct_bt
+
+#endif /* DBT_DEV_ACCOUNTING_HPP_ */
diff --git a/api/direct_bt/BTSecurityRegistry.hpp b/api/direct_bt/BTSecurityRegistry.hpp
new file mode 100644
index 00000000..ace42cd1
--- /dev/null
+++ b/api/direct_bt/BTSecurityRegistry.hpp
@@ -0,0 +1,103 @@
+/*
+ * Author: Sven Gothel <[email protected]>
+ * Copyright (c) 2020 Gothel Software e.K.
+ * Copyright (c) 2020 ZAFENA AB
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef DBT_SEC_SETTINGS_HPP_
+#define DBT_SEC_SETTINGS_HPP_
+
+#include <string>
+#include <cstdio>
+
+#include <direct_bt/DirectBT.hpp>
+
+namespace direct_bt {
+
+ /**
+ * Application toolkit providing BT security setup and its device association
+ * on a pattern matching basis, i.e. EUI48Sub or name-sub.
+ */
+ namespace BTSecurityRegistry {
+
+ struct Entry {
+ static constexpr int NO_PASSKEY = -1;
+
+ EUI48Sub addrSub;
+ std::string nameSub;
+
+ BTSecurityLevel sec_level { BTSecurityLevel::UNSET };
+ SMPIOCapability io_cap { SMPIOCapability::UNSET };
+ SMPIOCapability io_cap_auto { SMPIOCapability::UNSET };
+ int passkey = NO_PASSKEY;
+
+ Entry(const EUI48Sub& addrSub_)
+ : addrSub(addrSub_), nameSub() {}
+
+ Entry(const std::string& nameSub_)
+ : addrSub(EUI48Sub::ALL_DEVICE), nameSub(nameSub_) {}
+
+ bool matches(const EUI48Sub& addressSub) const noexcept {
+ return addrSub.length > 0 && addressSub.contains(addrSub);
+ }
+ bool matches(const EUI48& address) const noexcept {
+ return addrSub.length > 0 && address.contains(addrSub);
+ }
+ bool matches(const std::string& name) const noexcept {
+ return nameSub.length() > 0 && name.find(nameSub) != std::string::npos;
+ }
+
+ constexpr bool isSecLevelOrIOCapSet() const noexcept {
+ return SMPIOCapability::UNSET != io_cap || BTSecurityLevel::UNSET != sec_level;
+ }
+ constexpr const BTSecurityLevel& getSecLevel() const noexcept { return sec_level; }
+ constexpr const SMPIOCapability& getIOCap() const noexcept { return io_cap; }
+
+ constexpr bool isSecurityAutoEnabled() const noexcept {
+ return SMPIOCapability::UNSET != io_cap_auto;
+ }
+ constexpr const SMPIOCapability& getSecurityAutoIOCap() const noexcept { return io_cap_auto; }
+
+ constexpr int getPairingPasskey() const noexcept { return passkey; }
+
+ constexpr bool getPairingNumericComparison() const noexcept { return true; }
+
+ std::string toString() const noexcept {
+ const std::string id = addrSub == EUI48Sub::ALL_DEVICE ? "'"+nameSub+"'" : addrSub.toString();
+ return "BTSecurityDetail["+id+", lvl "+
+ to_string(sec_level)+
+ ", io "+to_string(io_cap)+
+ ", auto-io "+to_string(io_cap_auto)+
+ ", passkey "+std::to_string(passkey)+"]";
+ }
+ };
+ Entry* get(const EUI48& addr);
+ Entry* get(const EUI48Sub& addrSub);
+ Entry* get(const std::string& nameSub);
+ Entry* getOrCreate(const std::string& addrOrNameSub);
+ std::string allToString();
+
+ } // namespace BTSecurityRegistry
+
+} // namespace direct_bt
+
+#endif /* DBT_SEC_SETTINGS_HPP_ */
diff --git a/examples/direct_bt_scanner10/dbt_scanner10.cpp b/examples/direct_bt_scanner10/dbt_scanner10.cpp
index 9db08309..3ffb602b 100644
--- a/examples/direct_bt_scanner10/dbt_scanner10.cpp
+++ b/examples/direct_bt_scanner10/dbt_scanner10.cpp
@@ -44,6 +44,9 @@
#include <direct_bt/DirectBT.hpp>
+#include <direct_bt/BTDeviceRegistry.hpp>
+#include <direct_bt/BTSecurityRegistry.hpp>
+
extern "C" {
#include <unistd.h>
}
@@ -67,22 +70,32 @@ using namespace jau;
*
* * Read device C0:26:DA:01:DA:B1 (using default auto-sec w/ keyboard iocap)
* ~~~
- * ../scripts/run-dbt_scanner10.sh -mac C0:26:DA:01:DA:B1
+ * ../scripts/run-dbt_scanner10.sh -dev C0:26:DA:01:DA:B1
* ~~~
*
* * Read device C0:26:DA:01:DA:B1 (enforcing no security)
* ~~~
- * ../scripts/run-dbt_scanner10.sh -mac C0:26:DA:01:DA:B1 -seclevel C0:26:DA:01:DA:B1 1 1
+ * ../scripts/run-dbt_scanner10.sh -dev C0:26:DA:01:DA:B1 -seclevel C0:26:DA:01:DA:B1 1
+ * ~~~
+ *
+ * * Read any device containing C0:26:DA (enforcing no security)
+ * ~~~
+ * ../scripts/run-dbt_scanner10.sh -dev C0:26:DA -seclevel C0:26:DA 1
+ * ~~~
+ *
+ * * Read any device containing name `TAIDOC` (enforcing no security)
+ * ~~~
+ * ../scripts/run-dbt_scanner10.sh -dev 'TAIDOC' -seclevel 'TAIDOC' 1
* ~~~
*
* * Read device C0:26:DA:01:DA:B1, basic debug flags enabled (using default auto-sec w/ keyboard iocap)
* ~~~
- * ../scripts/run-dbt_scanner10.sh -mac C0:26:DA:01:DA:B1 -dbt_debug true
+ * ../scripts/run-dbt_scanner10.sh -dev C0:26:DA:01:DA:B1 -dbt_debug true
* ~~~
*
* * Read device C0:26:DA:01:DA:B1, all debug flags enabled (using default auto-sec w/ keyboard iocap)
* ~~~
- * ../scripts/run-dbt_scanner10.sh -mac C0:26:DA:01:DA:B1 -dbt_debug adapter.event,gatt.data,hci.event,hci.scan_ad_eir,mgmt.event
+ * ../scripts/run-dbt_scanner10.sh -dev C0:26:DA:01:DA:B1 -dbt_debug adapter.event,gatt.data,hci.event,hci.scan_ad_eir,mgmt.event
* ~~~
*
* ## Special Actions
@@ -93,7 +106,6 @@ using namespace jau;
* ~~~
*/
-const static int NO_PASSKEY = -1;
const static std::string KEY_PATH = "keys";
static uint64_t timestamp_t0;
@@ -116,8 +128,6 @@ static int charValue = 0;
static bool SHOW_UPDATE_EVENTS = false;
static bool QUIET = false;
-static jau::darray<BDAddressAndType> waitForDevices;
-
static void connectDiscoveredDevice(std::shared_ptr<BTDevice> device);
static void processReadyDevice(std::shared_ptr<BTDevice> device);
@@ -126,153 +136,6 @@ static void removeDevice(std::shared_ptr<BTDevice> device);
static void resetAdapter(BTAdapter *a, int mode);
static bool startDiscovery(BTAdapter *a, std::string msg);
-
-static std::unordered_set<BDAddressAndType> devicesInProcessing;
-static std::recursive_mutex mtx_devicesProcessing;
-
-static std::recursive_mutex mtx_devicesProcessed;
-static std::unordered_set<BDAddressAndType> devicesProcessed;
-
-bool matches(jau::darray<BDAddressAndType> &cont, const BDAddressAndType &mac) {
- return cont.end() != jau::find_if(cont.begin(), cont.end(), [&](const BDAddressAndType & it)->bool {
- return it.matches(mac);
- });
-}
-
-void printList(const std::string &msg, jau::darray<BDAddressAndType> &cont) {
- fprintf_td(stderr, "%s ", msg.c_str());
- jau::for_each(cont.begin(), cont.end(),
- [](const BDAddressAndType &mac) { fprintf_td(stderr, "%s, ", mac.toString().c_str()); });
- fprintf_td(stderr, "\n");
-}
-
-void printList(const std::string &msg, std::unordered_set<BDAddressAndType> &cont) {
- fprintf_td(stderr, "%s ", msg.c_str());
- jau::for_each(cont.begin(), cont.end(),
- [](const BDAddressAndType &mac) { fprintf_td(stderr, "%s, ", mac.toString().c_str()); });
- fprintf_td(stderr, "\n");
-}
-
-static void addToDevicesProcessed(const BDAddressAndType &a) {
- const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessed); // RAII-style acquire and relinquish via destructor
- devicesProcessed.insert(devicesProcessed.end(), a);
-}
-static bool isDeviceProcessed(const BDAddressAndType & a) {
- const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessed); // RAII-style acquire and relinquish via destructor
- return devicesProcessed.end() != devicesProcessed.find(a);
-}
-static size_t getDeviceProcessedCount() {
- const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessed); // RAII-style acquire and relinquish via destructor
- return devicesProcessed.size();
-}
-static bool allDevicesProcessed(jau::darray<BDAddressAndType> &cont) {
- const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessed); // RAII-style acquire and relinquish via destructor
- for (auto it = cont.begin(); it != cont.end(); ++it) {
- if( devicesProcessed.end() == devicesProcessed.find(*it) ) {
- return false;
- }
- }
- return true;
-}
-static void printDevicesProcessed(const std::string &msg) {
- const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessed); // RAII-style acquire and relinquish via destructor
- printList(msg, devicesProcessed);
-}
-
-static void addToDevicesProcessing(const BDAddressAndType &a) {
- const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessing); // RAII-style acquire and relinquish via destructor
- devicesInProcessing.insert(devicesInProcessing.end(), a);
-}
-static bool removeFromDevicesProcessing(const BDAddressAndType &a) {
- const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessing); // RAII-style acquire and relinquish via destructor
- for (auto it = devicesInProcessing.begin(); it != devicesInProcessing.end(); ++it) {
- if ( a == *it ) {
- devicesInProcessing.erase(it);
- return true;
- }
- }
- return false;
-}
-static bool isDeviceProcessing(const BDAddressAndType & a) {
- const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessing); // RAII-style acquire and relinquish via destructor
- return devicesInProcessing.end() != devicesInProcessing.find(a);
-}
-static size_t getDeviceProcessingCount() {
- const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessing); // RAII-style acquire and relinquish via destructor
- return devicesInProcessing.size();
-}
-
-struct MyBTSecurityDetail {
- BDAddressAndType addrAndType;
-
- BTSecurityLevel sec_level { BTSecurityLevel::UNSET };
- SMPIOCapability io_cap { SMPIOCapability::UNSET };
- SMPIOCapability io_cap_auto { SMPIOCapability::UNSET };
- int passkey = NO_PASSKEY;
-
- MyBTSecurityDetail(const BDAddressAndType& addrAndType_)
- : addrAndType(addrAndType_) {}
-
- constexpr bool isSecLevelOrIOCapSet() const noexcept {
- return SMPIOCapability::UNSET != io_cap || BTSecurityLevel::UNSET != sec_level;
- }
- constexpr const BTSecurityLevel& getSecLevel() const noexcept { return sec_level; }
- constexpr const SMPIOCapability& getIOCap() const noexcept { return io_cap; }
-
- constexpr bool isSecurityAutoEnabled() const noexcept {
- return SMPIOCapability::UNSET != io_cap_auto;
- }
- constexpr const SMPIOCapability& getSecurityAutoIOCap() const noexcept { return io_cap_auto; }
-
- constexpr int getPairingPasskey() const noexcept { return passkey; }
-
- constexpr bool getPairingNumericComparison() const noexcept { return true; }
-
- std::string toString() const noexcept {
- return "MyBTSecurityDetail["+addrAndType.toString()+", lvl "+
- to_string(sec_level)+
- ", io "+to_string(io_cap)+
- ", auto-io "+to_string(io_cap_auto)+
- ", passkey "+std::to_string(passkey)+"]";
- }
-
- private:
- static std::unordered_map<BDAddressAndType, MyBTSecurityDetail> devicesSecDetail;
-
- public:
-
- static MyBTSecurityDetail* get(const BDAddressAndType& addrAndType) {
- auto s = devicesSecDetail.find(addrAndType);
- if( s != devicesSecDetail.end() ) {
- return &(s->second);
- } else {
- return nullptr;
- }
- }
- static MyBTSecurityDetail* getOrCreate(const BDAddressAndType& addrAndType) {
- MyBTSecurityDetail* sec_detail = get(addrAndType);
- if( nullptr != sec_detail ) {
- return sec_detail;
- } else {
- auto i = devicesSecDetail.insert( devicesSecDetail.end(), { addrAndType, MyBTSecurityDetail(addrAndType) } );
- return &(i->second);
- }
- }
- static std::string allToString() {
- std::string res;
- int i=0;
- for(auto iter = devicesSecDetail.begin(); iter != devicesSecDetail.end(); ++iter, ++i) {
- const MyBTSecurityDetail& sec = iter->second;
- if( 0 < i ) {
- res += ", ";
- }
- res += sec.toString();
- }
- return res;
- }
-};
-std::unordered_map<BDAddressAndType, MyBTSecurityDetail> MyBTSecurityDetail::devicesSecDetail;
-
class MyAdapterStatusListener : public AdapterStatusListener {
void adapterSettingsChanged(BTAdapter &a, const AdapterSetting oldmask, const AdapterSetting newmask,
@@ -313,10 +176,10 @@ class MyAdapterStatusListener : public AdapterStatusListener {
fprintf_td(stderr, "****** FOUND__-2: Skip non 'public LE' and non 'random static public LE' %s\n", device->toString(true).c_str());
return false;
}
- if( !isDeviceProcessing( device->getAddressAndType() ) &&
- ( waitForDevices.empty() ||
- ( matches(waitForDevices, device->getAddressAndType()) &&
- ( 0 < MULTI_MEASUREMENTS || !isDeviceProcessed(device->getAddressAndType()) )
+ if( !BTDeviceRegistry::isDeviceProcessing( device->getAddressAndType() ) &&
+ ( !BTDeviceRegistry::isWaitingForAnyDevice() ||
+ ( BTDeviceRegistry::isWaitingForDevice(device->getAddressAndType(), device->getName()) &&
+ ( 0 < MULTI_MEASUREMENTS || !BTDeviceRegistry::isDeviceProcessed(device->getAddressAndType()) )
)
)
)
@@ -372,8 +235,8 @@ class MyAdapterStatusListener : public AdapterStatusListener {
// next: PASSKEY_EXPECTED... or KEY_DISTRIBUTION
break;
case SMPPairingState::PASSKEY_EXPECTED: {
- const MyBTSecurityDetail* sec = MyBTSecurityDetail::get(device->getAddressAndType());
- if( nullptr != sec && sec->getPairingPasskey() != NO_PASSKEY ) {
+ const BTSecurityRegistry::Entry* sec = BTSecurityRegistry::get(device->getAddressAndType().address);
+ if( nullptr != sec && sec->getPairingPasskey() != BTSecurityRegistry::Entry::NO_PASSKEY ) {
std::thread dc(&BTDevice::setPairingPasskey, device, static_cast<uint32_t>( sec->getPairingPasskey() ));
dc.detach();
} else {
@@ -384,7 +247,7 @@ class MyAdapterStatusListener : public AdapterStatusListener {
// next: KEY_DISTRIBUTION or FAILED
} break;
case SMPPairingState::NUMERIC_COMPARE_EXPECTED: {
- const MyBTSecurityDetail* sec = MyBTSecurityDetail::get(device->getAddressAndType());
+ const BTSecurityRegistry::Entry* sec = BTSecurityRegistry::get(device->getAddressAndType().address);
if( nullptr != sec ) {
std::thread dc(&BTDevice::setPairingNumericComparison, device, sec->getPairingNumericComparison());
dc.detach();
@@ -410,17 +273,17 @@ class MyAdapterStatusListener : public AdapterStatusListener {
void deviceReady(std::shared_ptr<BTDevice> device, const uint64_t timestamp) override {
(void)timestamp;
- if( !isDeviceProcessing( device->getAddressAndType() ) &&
- ( waitForDevices.empty() ||
- ( matches(waitForDevices, device->getAddressAndType()) &&
- ( 0 < MULTI_MEASUREMENTS || !isDeviceProcessed(device->getAddressAndType()) )
+ if( !BTDeviceRegistry::isDeviceProcessing( device->getAddressAndType() ) &&
+ ( !BTDeviceRegistry::isWaitingForAnyDevice() ||
+ ( BTDeviceRegistry::isWaitingForDevice(device->getAddressAndType(), device->getName()) &&
+ ( 0 < MULTI_MEASUREMENTS || !BTDeviceRegistry::isDeviceProcessed(device->getAddressAndType()) )
)
)
)
{
deviceReadyCount++;
fprintf_td(stderr, "****** READY-0: Processing[%d] %s\n", deviceReadyCount.load(), device->toString(true).c_str());
- addToDevicesProcessing(device->getAddressAndType());
+ BTDeviceRegistry::addToDevicesProcessing(device->getAddressAndType(), device->getName());
processReadyDevice(device); // AdapterStatusListener::deviceReady() explicitly allows prolonged and complex code execution!
} else {
fprintf_td(stderr, "****** READY-1: NOP %s\n", device->toString(true).c_str());
@@ -437,7 +300,7 @@ class MyAdapterStatusListener : public AdapterStatusListener {
std::thread dc(::removeDevice, device); // @suppress("Invalid arguments")
dc.detach();
} else {
- removeFromDevicesProcessing(device->getAddressAndType());
+ BTDeviceRegistry::removeFromDevicesProcessing(device->getAddressAndType());
}
if( 0 < RESET_ADAPTER_EACH_CONN && 0 == deviceReadyCount % RESET_ADAPTER_EACH_CONN ) {
std::thread dc(::resetAdapter, &device->getAdapter(), 1); // @suppress("Invalid arguments")
@@ -523,7 +386,7 @@ static void connectDiscoveredDevice(std::shared_ptr<BTDevice> device) {
fprintf_td(stderr, "****** Connecting Device: stopDiscovery result %s\n", to_string(r).c_str());
}
- const MyBTSecurityDetail* sec = MyBTSecurityDetail::get(device->getAddressAndType());
+ const BTSecurityRegistry::Entry* sec = BTSecurityRegistry::get(device->getAddressAndType().address);
const BTSecurityLevel req_sec_level = nullptr != sec ? sec->getSecLevel() : BTSecurityLevel::UNSET;
HCIStatusCode res = SMPKeyBin::readAndApply(KEY_PATH, *device, req_sec_level, true /* verbose */);
fprintf_td(stderr, "****** Connecting Device: SMPKeyBin::readAndApply(..) result %s\n", to_string(res).c_str());
@@ -553,7 +416,7 @@ static void connectDiscoveredDevice(std::shared_ptr<BTDevice> device) {
}
fprintf_td(stderr, "****** Connecting Device: End result %s of %s\n", to_string(res).c_str(), device->toString().c_str());
- if( !USE_WHITELIST && 0 == getDeviceProcessingCount() && HCIStatusCode::SUCCESS != res ) {
+ if( !USE_WHITELIST && 0 == BTDeviceRegistry::getDeviceProcessingCount() && HCIStatusCode::SUCCESS != res ) {
startDiscovery(&device->getAdapter(), "post-connect");
}
}
@@ -685,11 +548,11 @@ static void processReadyDevice(std::shared_ptr<BTDevice> device) {
exit:
fprintf_td(stderr, "****** Processing Ready Device: End-1: Success %d on %s; devInProc %zu\n",
- success, device->toString().c_str(), getDeviceProcessingCount());
+ success, device->toString().c_str(), BTDeviceRegistry::getDeviceProcessingCount());
- removeFromDevicesProcessing(device->getAddressAndType());
+ BTDeviceRegistry::removeFromDevicesProcessing(device->getAddressAndType());
- if( !USE_WHITELIST && 0 == getDeviceProcessingCount() ) {
+ if( !USE_WHITELIST && 0 == BTDeviceRegistry::getDeviceProcessingCount() ) {
startDiscovery(&device->getAdapter(), "post-processing-1");
}
@@ -707,10 +570,10 @@ exit:
}
fprintf_td(stderr, "****** Processing Ready Device: End-2: Success %d on %s; devInProc %zu\n",
- success, device->toString().c_str(), getDeviceProcessingCount());
+ success, device->toString().c_str(), BTDeviceRegistry::getDeviceProcessingCount());
if( success ) {
- addToDevicesProcessed(device->getAddressAndType());
+ BTDeviceRegistry::addToDevicesProcessed(device->getAddressAndType(), device->getName());
}
device->removeAllCharListener();
@@ -724,7 +587,7 @@ exit:
if( 0 < RESET_ADAPTER_EACH_CONN && 0 == deviceReadyCount % RESET_ADAPTER_EACH_CONN ) {
resetAdapter(&device->getAdapter(), 2);
- } else if( !USE_WHITELIST && 0 == getDeviceProcessingCount() ) {
+ } else if( !USE_WHITELIST && 0 == BTDeviceRegistry::getDeviceProcessingCount() ) {
startDiscovery(&device->getAdapter(), "post-processing-2");
}
}
@@ -739,11 +602,11 @@ static void removeDevice(std::shared_ptr<BTDevice> device) {
fprintf_td(stderr, "****** Remove Device: removing: %s\n", device->getAddressAndType().toString().c_str());
device->getAdapter().stopDiscovery();
- removeFromDevicesProcessing(device->getAddressAndType());
+ BTDeviceRegistry::removeFromDevicesProcessing(device->getAddressAndType());
device->remove();
- if( !USE_WHITELIST && 0 == getDeviceProcessingCount() ) {
+ if( !USE_WHITELIST && 0 == BTDeviceRegistry::getDeviceProcessingCount() ) {
startDiscovery(&device->getAdapter(), "post-remove-device");
}
}
@@ -754,7 +617,7 @@ static void resetAdapter(BTAdapter *a, int mode) {
fprintf_td(stderr, "****** Reset Adapter: reset[%d] end: %s, %s\n", mode, to_string(res).c_str(), a->toString().c_str());
}
-static bool le_scan_active = false; // default value
+static bool le_scan_active = true; // default value
static const uint16_t le_scan_interval = 24; // default value
static const uint16_t le_scan_window = 24; // default value
static const uint8_t filter_policy = 0; // default value
@@ -774,15 +637,7 @@ static bool initAdapter(std::shared_ptr<BTAdapter>& adapter) {
// Flush discovered devices after registering our status listener.
// This avoids discovered devices before we have registered!
- if( 0 == waitForDevices.size() ) {
- // we accept all devices, so flush all discovered devices
- adapter->removeDiscoveredDevices();
- } else {
- // only flush discovered devices we intend to listen to
- jau::for_each(waitForDevices.begin(), waitForDevices.end(), [&adapter](const BDAddressAndType &mac) {
- adapter->removeDiscoveredDevice(mac);
- });
- }
+ adapter->removeDiscoveredDevices();
if( USE_WHITELIST ) {
for (auto it = WHITELIST.begin(); it != WHITELIST.end(); ++it) {
@@ -820,13 +675,13 @@ void test() {
while( !done ) {
if( 0 == MULTI_MEASUREMENTS ||
- ( -1 == MULTI_MEASUREMENTS && !waitForDevices.empty() && allDevicesProcessed(waitForDevices) )
+ ( -1 == MULTI_MEASUREMENTS && BTDeviceRegistry::isWaitingForAnyDevice() && BTDeviceRegistry::allDevicesProcessed() )
)
{
fprintf_td(stderr, "****** EOL Test MULTI_MEASUREMENTS left %d, processed %zu/%zu\n",
- MULTI_MEASUREMENTS.load(), getDeviceProcessedCount(), (size_t)waitForDevices.size());
- printList("****** WaitForDevice ", waitForDevices);
- printDevicesProcessed("****** DevicesProcessed ");
+ MULTI_MEASUREMENTS.load(), BTDeviceRegistry::getDeviceProcessedCount(), BTDeviceRegistry::getWaitForDevicesCount());
+ BTDeviceRegistry::printWaitForDevices(stderr, "****** WaitForDevice ");
+ BTDeviceRegistry::printDevicesProcessed(stderr, "****** DevicesProcessed ");
done = true;
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
@@ -885,44 +740,35 @@ int main(int argc, char *argv[])
SHOW_UPDATE_EVENTS = true;
} else if( !strcmp("-quiet", argv[i]) ) {
QUIET = true;
- } else if( !strcmp("-scanActive", argv[i]) ) {
- le_scan_active = true;
- } else if( !strcmp("-mac", argv[i]) && argc > (i+1) ) {
- std::string macstr = std::string(argv[++i]);
- BDAddressAndType mac(EUI48(macstr), BDAddressType::BDADDR_UNDEFINED);
- waitForDevices.push_back( mac );
+ } else if( !strcmp("-scanPassive", argv[i]) ) {
+ le_scan_active = false;
+ } else if( !strcmp("-dev", argv[i]) && argc > (i+1) ) {
+ std::string addrOrNameSub = std::string(argv[++i]);
+ BTDeviceRegistry::addToWaitForDevices( addrOrNameSub );
} else if( !strcmp("-wl", argv[i]) && argc > (i+1) ) {
std::string macstr = std::string(argv[++i]);
BDAddressAndType wle(EUI48(macstr), BDAddressType::BDADDR_LE_PUBLIC);
fprintf(stderr, "Whitelist + %s\n", wle.toString().c_str());
WHITELIST.push_back( wle );
USE_WHITELIST = true;
- } else if( !strcmp("-passkey", argv[i]) && argc > (i+3) ) {
- const char* mac = argv[++i];
- const uint8_t atype = (uint8_t) ( atoi(argv[++i]) & 0xff );
- const BDAddressAndType macAndType(EUI48(mac), to_BDAddressType(atype));
- MyBTSecurityDetail* sec = MyBTSecurityDetail::getOrCreate(macAndType);
+ } else if( !strcmp("-passkey", argv[i]) && argc > (i+2) ) {
+ const std::string addrOrNameSub(argv[++i]);
+ BTSecurityRegistry::Entry* sec = BTSecurityRegistry::getOrCreate(addrOrNameSub);
sec->passkey = atoi(argv[++i]);
fprintf(stderr, "Set passkey in %s\n", sec->toString().c_str());
- } else if( !strcmp("-seclevel", argv[i]) && argc > (i+3) ) {
- const char* mac = argv[++i];
- const uint8_t atype = (uint8_t) ( atoi(argv[++i]) & 0xff );
- const BDAddressAndType macAndType(EUI48(mac), to_BDAddressType(atype));
- MyBTSecurityDetail* sec = MyBTSecurityDetail::getOrCreate(macAndType);
+ } else if( !strcmp("-seclevel", argv[i]) && argc > (i+2) ) {
+ const std::string addrOrNameSub(argv[++i]);
+ BTSecurityRegistry::Entry* sec = BTSecurityRegistry::getOrCreate(addrOrNameSub);
sec->sec_level = to_BTSecurityLevel(atoi(argv[++i]));
fprintf(stderr, "Set sec_level in %s\n", sec->toString().c_str());
- } else if( !strcmp("-iocap", argv[i]) && argc > (i+3) ) {
- const char* mac = argv[++i];
- const uint8_t atype = (uint8_t) ( atoi(argv[++i]) & 0xff );
- const BDAddressAndType macAndType(EUI48(mac), to_BDAddressType(atype));
- MyBTSecurityDetail* sec = MyBTSecurityDetail::getOrCreate(macAndType);
+ } else if( !strcmp("-iocap", argv[i]) && argc > (i+2) ) {
+ const std::string addrOrNameSub(argv[++i]);
+ BTSecurityRegistry::Entry* sec = BTSecurityRegistry::getOrCreate(addrOrNameSub);
sec->io_cap = to_SMPIOCapability(atoi(argv[++i]));
fprintf(stderr, "Set io_cap in %s\n", sec->toString().c_str());
- } else if( !strcmp("-secauto", argv[i]) && argc > (i+3) ) {
- const char* mac = argv[++i];
- const uint8_t atype = (uint8_t) ( atoi(argv[++i]) & 0xff );
- const BDAddressAndType macAndType(EUI48(mac), to_BDAddressType(atype));
- MyBTSecurityDetail* sec = MyBTSecurityDetail::getOrCreate(macAndType);
+ } else if( !strcmp("-secauto", argv[i]) && argc > (i+2) ) {
+ const std::string addrOrNameSub(argv[++i]);
+ BTSecurityRegistry::Entry* sec = BTSecurityRegistry::getOrCreate(addrOrNameSub);
sec->io_cap_auto = to_SMPIOCapability(atoi(argv[++i]));
fprintf(stderr, "Set SEC AUTO security io_cap in %s\n", sec->toString().c_str());
} else if( !strcmp("-charid", argv[i]) && argc > (i+1) ) {
@@ -947,13 +793,13 @@ int main(int argc, char *argv[])
fprintf(stderr, "Run with '[-btmode LE|BREDR|DUAL] "
"[-disconnect] [-enableGATTPing] [-count <number>] [-single] [-show_update_events] [-quiet] "
- "[-scanActive]"
+ "[-scanPassive]"
"[-resetEachCon connectionCount] "
- "(-mac <device_address>)* (-wl <device_address>)* "
- "[-seclevel <device_address> <(int)address_type> <int>] "
- "[-iocap <device_address> <(int)address_type> <int>] "
- "[-secauto <device_address> <(int)address_type> <int>] "
- "[-passkey <device_address> <(int)address_type> <digits>] "
+ "(-dev <device_[address|name]_sub>)* (-wl <device_address>)* "
+ "(-seclevel <device_[address|name]_sub> <int_sec_level>)* "
+ "(-iocap <device_[address|name]_sub> <int_iocap>)* "
+ "(-secauto <device_[address|name]_sub> <int_iocap>)* "
+ "(-passkey <device_[address|name]_sub> <digits>)* "
"[-unpairPre] [-unpairPost] "
"[-charid <uuid>] [-charval <byte-val>] "
"[-dbt_verbose true|false] "
@@ -977,8 +823,8 @@ int main(int argc, char *argv[])
fprintf(stderr, "characteristic-id: %s\n", charIdentifier.c_str());
fprintf(stderr, "characteristic-value: %d\n", charValue);
- fprintf(stderr, "security-details: %s\n", MyBTSecurityDetail::allToString().c_str());
- printList( "waitForDevice: ", waitForDevices);
+ fprintf(stderr, "security-details: %s\n", BTSecurityRegistry::allToString().c_str());
+ BTDeviceRegistry::printWaitForDevices(stderr, "waitForDevice: ");
if( waitForEnter ) {
diff --git a/examples/java/DBTScanner10.java b/examples/java/DBTScanner10.java
index 9839e3f6..6daf1ee4 100644
--- a/examples/java/DBTScanner10.java
+++ b/examples/java/DBTScanner10.java
@@ -26,10 +26,6 @@
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@@ -44,6 +40,7 @@ import org.direct_bt.BTMode;
import org.direct_bt.BTSecurityLevel;
import org.direct_bt.BTAdapter;
import org.direct_bt.BTDevice;
+import org.direct_bt.BTDeviceRegistry;
import org.direct_bt.BTException;
import org.direct_bt.BTFactory;
import org.direct_bt.BTGattChar;
@@ -51,6 +48,7 @@ import org.direct_bt.BTGattDesc;
import org.direct_bt.BTGattService;
import org.direct_bt.BTManager;
import org.direct_bt.BTNotification;
+import org.direct_bt.BTSecurityRegistry;
import org.direct_bt.BTType;
import org.direct_bt.BTUtils;
import org.direct_bt.EIRDataTypeSet;
@@ -61,7 +59,6 @@ import org.direct_bt.HCIWhitelistConnectType;
import org.direct_bt.PairingMode;
import org.direct_bt.SMPIOCapability;
import org.direct_bt.SMPKeyBin;
-import org.direct_bt.SMPKeyMask;
import org.direct_bt.SMPPairingState;
import org.direct_bt.ScanType;
@@ -74,13 +71,13 @@ import jau.direct_bt.DBTManager;
* <p>
* This example represents the recommended utilization of Direct-BT.
* </p>
+ * <p>
+ * See `dbt_scanner10.cpp` for invocation examples, since both apps are fully compatible.
+ * </p>
*/
public class DBTScanner10 {
- static final int NO_PASSKEY = -1;
static final String KEY_PATH = "keys";
- final List<BDAddressAndType> waitForDevices = new ArrayList<BDAddressAndType>();
-
long timestamp_t0;
int RESET_ADAPTER_EACH_CONN = 0;
@@ -137,53 +134,6 @@ public class DBTScanner10 {
}
}
- static public class MyBTSecurityDetail {
- public final BDAddressAndType addrAndType;
-
- BTSecurityLevel sec_level = BTSecurityLevel.UNSET;
- SMPIOCapability io_cap = SMPIOCapability.UNSET;
- SMPIOCapability io_cap_auto = SMPIOCapability.UNSET;
- int passkey = NO_PASSKEY;
-
- public MyBTSecurityDetail(final BDAddressAndType addrAndType) { this.addrAndType = addrAndType; }
-
- public boolean isSecLevelOrIOCapSet() {
- return SMPIOCapability.UNSET != io_cap || BTSecurityLevel.UNSET != sec_level;
- }
- public BTSecurityLevel getSecLevel() { return sec_level; }
- public SMPIOCapability getIOCap() { return io_cap; }
-
- public boolean isSecurityAutoEnabled() { return SMPIOCapability.UNSET != io_cap_auto; }
- public SMPIOCapability getSecurityAutoIOCap() { return io_cap_auto; }
-
- public int getPairingPasskey() { return passkey; }
-
- public boolean getPairingNumericComparison() { return true; }
-
- @Override
- public String toString() {
- return "BTSecurityDetail["+addrAndType+", lvl "+sec_level+", io "+io_cap+", auto-io "+io_cap_auto+", passkey "+passkey+"]";
- }
-
- static private HashMap<BDAddressAndType, MyBTSecurityDetail> devicesSecDetail = new HashMap<BDAddressAndType, MyBTSecurityDetail>();
-
- static public MyBTSecurityDetail get(final BDAddressAndType addrAndType) {
- return devicesSecDetail.get(addrAndType);
- }
- static public MyBTSecurityDetail getOrCreate(final BDAddressAndType addrAndType) {
- MyBTSecurityDetail sec_detail = devicesSecDetail.get(addrAndType);
- if( null == sec_detail ) {
- sec_detail = new MyBTSecurityDetail(addrAndType);
- devicesSecDetail.put(addrAndType, sec_detail);
- }
- return sec_detail;
- }
- static public String allToString() { return Arrays.toString( devicesSecDetail.values().toArray() ); }
- }
-
- Collection<BDAddressAndType> devicesInProcessing = Collections.synchronizedCollection(new HashSet<>());
- Collection<BDAddressAndType> devicesProcessed = Collections.synchronizedCollection(new HashSet<>());
-
final AdapterStatusListener statusListener = new AdapterStatusListener() {
@Override
public void adapterSettingsChanged(final BTAdapter adapter, final AdapterSettings oldmask,
@@ -221,10 +171,10 @@ public class DBTScanner10 {
BTUtils.println(System.err, "****** FOUND__-2: Skip non 'public LE' and non 'random static public LE' "+device.toString());
return false;
}
- if( !devicesInProcessing.contains( device.getAddressAndType() ) &&
- ( waitForDevices.isEmpty() ||
- ( matches(waitForDevices, device.getAddressAndType() ) &&
- ( 0 < MULTI_MEASUREMENTS.get() || !devicesProcessed.contains( device.getAddressAndType() ) )
+ if( !BTDeviceRegistry.isDeviceProcessing( device.getAddressAndType() ) &&
+ ( !BTDeviceRegistry.isWaitingForAnyDevice() ||
+ ( BTDeviceRegistry.isWaitingForDevice(device.getAddressAndType(), device.getName()) &&
+ ( 0 < MULTI_MEASUREMENTS.get() || !BTDeviceRegistry.isDeviceProcessed(device.getAddressAndType()) )
)
)
)
@@ -277,8 +227,8 @@ public class DBTScanner10 {
// next: PASSKEY_EXPECTED... or KEY_DISTRIBUTION
break;
case PASSKEY_EXPECTED: {
- final MyBTSecurityDetail sec = MyBTSecurityDetail.get(device.getAddressAndType());
- if( null != sec && sec.getPairingPasskey() != NO_PASSKEY ) {
+ final BTSecurityRegistry.Entry sec = BTSecurityRegistry.get(device.getAddressAndType().address);
+ if( null != sec && sec.getPairingPasskey() != BTSecurityRegistry.NO_PASSKEY ) {
executeOffThread( () -> { device.setPairingPasskey( sec.getPairingPasskey() ); }, "DBT-SetPasskey-"+device.getAddressAndType(), true /* detach */);
} else {
executeOffThread( () -> { device.setPairingPasskey( 0 ); }, "DBT-SetPasskey-"+device.getAddressAndType(), true /* detach */);
@@ -287,7 +237,7 @@ public class DBTScanner10 {
// next: KEY_DISTRIBUTION or FAILED
} break;
case NUMERIC_COMPARE_EXPECTED: {
- final MyBTSecurityDetail sec = MyBTSecurityDetail.get(device.getAddressAndType());
+ final BTSecurityRegistry.Entry sec = BTSecurityRegistry.get(device.getAddressAndType().address);
if( null != sec ) {
executeOffThread( () -> { device.setPairingNumericComparison( sec.getPairingNumericComparison() ); }, "DBT-SetNumericComp-"+device.getAddressAndType(), true /* detach */);
} else {
@@ -311,10 +261,10 @@ public class DBTScanner10 {
@Override
public void deviceReady(final BTDevice device, final long timestamp) {
- if( !devicesInProcessing.contains( device.getAddressAndType() ) &&
- ( waitForDevices.isEmpty() ||
- ( matches(waitForDevices, device.getAddressAndType() ) &&
- ( 0 < MULTI_MEASUREMENTS.get() || !devicesProcessed.contains( device.getAddressAndType() ) )
+ if( !BTDeviceRegistry.isDeviceProcessing( device.getAddressAndType() ) &&
+ ( !BTDeviceRegistry.isWaitingForAnyDevice() ||
+ ( BTDeviceRegistry.isWaitingForDevice(device.getAddressAndType(), device.getName()) &&
+ ( 0 < MULTI_MEASUREMENTS.get() || !BTDeviceRegistry.isDeviceProcessed(device.getAddressAndType()) )
)
)
)
@@ -325,7 +275,7 @@ public class DBTScanner10 {
final long td = BTUtils.currentTimeMillis() - timestamp_t0; // adapter-init -> now
BTUtils.println(System.err, "PERF: adapter-init -> READY-0 " + td + " ms");
}
- devicesInProcessing.add(device.getAddressAndType());
+ BTDeviceRegistry.addToDevicesProcessing(device.getAddressAndType(), device.getName());
processReadyDevice(device); // AdapterStatusListener::deviceReady() explicitly allows prolonged and complex code execution!
} else {
BTUtils.println(System.err, "****** READY-1: NOP " + device.toString());
@@ -339,7 +289,7 @@ public class DBTScanner10 {
if( REMOVE_DEVICE ) {
executeOffThread( () -> { removeDevice(device); }, "DBT-Remove-"+device.getAddressAndType(), true /* detach */);
} else {
- devicesInProcessing.remove(device.getAddressAndType());
+ BTDeviceRegistry.removeFromDevicesProcessing(device.getAddressAndType());
}
if( 0 < RESET_ADAPTER_EACH_CONN && 0 == deviceReadyCount.get() % RESET_ADAPTER_EACH_CONN ) {
executeOffThread( () -> { resetAdapter(device.getAdapter(), 1); },
@@ -384,7 +334,7 @@ public class DBTScanner10 {
BTUtils.println(System.err, "****** Connecting Device: stopDiscovery result "+r);
}
- final MyBTSecurityDetail sec = MyBTSecurityDetail.get(device.getAddressAndType());
+ final BTSecurityRegistry.Entry sec = BTSecurityRegistry.get(device.getAddressAndType().address);
final BTSecurityLevel req_sec_level = null != sec ? sec.getSecLevel() : BTSecurityLevel.UNSET;
HCIStatusCode res = SMPKeyBin.readAndApply(KEY_PATH, device, req_sec_level, true /* verbose */);
BTUtils.fprintf_td(System.err, "****** Connecting Device: SMPKeyBin::readAndApply(..) result %s\n", res.toString());
@@ -414,7 +364,7 @@ public class DBTScanner10 {
}
BTUtils.println(System.err, "****** Connecting Device Command, res "+res+": End result "+res+" of " + device.toString());
- if( !USE_WHITELIST && 0 == devicesInProcessing.size() && HCIStatusCode.SUCCESS != res ) {
+ if( !USE_WHITELIST && 0 == BTDeviceRegistry.getDeviceProcessingCount() && HCIStatusCode.SUCCESS != res ) {
startDiscovery(device.getAdapter(), "post-connect");
}
}
@@ -596,11 +546,11 @@ public class DBTScanner10 {
}
BTUtils.println(System.err, "****** Processing Ready Device: End-1: Success " + success +
- " on " + device.toString() + "; devInProc "+devicesInProcessing.size());
+ " on " + device.toString() + "; devInProc "+BTDeviceRegistry.getDeviceProcessingCount());
- devicesInProcessing.remove(device.getAddressAndType());
+ BTDeviceRegistry.removeFromDevicesProcessing( device.getAddressAndType() );
- if( !USE_WHITELIST && 0 == devicesInProcessing.size() ) {
+ if( !USE_WHITELIST && 0 == BTDeviceRegistry.getDeviceProcessingCount() ) {
startDiscovery(device.getAdapter(), "post-processing-1");
}
@@ -618,9 +568,9 @@ public class DBTScanner10 {
}
BTUtils.println(System.err, "****** Processing Ready Device: End-2: Success " + success +
- " on " + device.toString() + "; devInProc "+devicesInProcessing.size());
+ " on " + device.toString() + "; devInProc "+BTDeviceRegistry.getDeviceProcessingCount());
if( success ) {
- devicesProcessed.add(device.getAddressAndType());
+ BTDeviceRegistry.addToDevicesProcessed(device.getAddressAndType(), device.getName());
}
device.removeAllCharListener();
@@ -635,7 +585,7 @@ public class DBTScanner10 {
if( 0 < RESET_ADAPTER_EACH_CONN && 0 == deviceReadyCount.get() % RESET_ADAPTER_EACH_CONN ) {
resetAdapter(device.getAdapter(), 2);
- } else if( !USE_WHITELIST && 0 == devicesInProcessing.size() ) {
+ } else if( !USE_WHITELIST && 0 == BTDeviceRegistry.getDeviceProcessingCount() ) {
startDiscovery(device.getAdapter(), "post-processing-2");
}
}
@@ -650,11 +600,11 @@ public class DBTScanner10 {
BTUtils.println(System.err, "****** Remove Device: removing: "+device.getAddressAndType());
device.getAdapter().stopDiscovery();
- devicesInProcessing.remove(device.getAddressAndType());
+ BTDeviceRegistry.removeFromDevicesProcessing(device.getAddressAndType());
device.remove();
- if( !USE_WHITELIST && 0 == devicesInProcessing.size() ) {
+ if( !USE_WHITELIST && 0 == BTDeviceRegistry.getDeviceProcessingCount() ) {
startDiscovery(device.getAdapter(), "post-remove-device");
}
}
@@ -665,7 +615,7 @@ public class DBTScanner10 {
BTUtils.println(System.err, "****** Reset Adapter: reset["+mode+"] end: "+res+", "+adapter.toString());
}
- static boolean le_scan_active = false; // default value
+ static boolean le_scan_active = true; // default value
static final short le_scan_interval = (short)24; // default value
static final short le_scan_window = (short)24; // default value
static final byte filter_policy = (byte)0; // default value
@@ -693,15 +643,7 @@ public class DBTScanner10 {
// Flush discovered devices after registering our status listener.
// This avoids discovered devices before we have registered!
- if( 0 == waitForDevices.size() ) {
- // we accept all devices, so flush all discovered devices
- adapter.removeDiscoveredDevices();
- } else {
- // only flush discovered devices we intend to listen to
- for( final Iterator<BDAddressAndType> iter=waitForDevices.iterator(); iter.hasNext(); ) {
- adapter.removeDiscoveredDevice( iter.next() );
- }
- }
+ adapter.removeDiscoveredDevices();
if( USE_WHITELIST ) {
for(final Iterator<BDAddressAndType> wliter = whitelist.iterator(); wliter.hasNext(); ) {
@@ -743,13 +685,13 @@ public class DBTScanner10 {
while( !done ) {
if( 0 == MULTI_MEASUREMENTS.get() ||
- ( -1 == MULTI_MEASUREMENTS.get() && !waitForDevices.isEmpty() && devicesProcessed.containsAll(waitForDevices) )
+ ( -1 == MULTI_MEASUREMENTS.get() && BTDeviceRegistry.isWaitingForAnyDevice() && BTDeviceRegistry.allDevicesProcessed() )
)
{
BTUtils.println(System.err, "****** EOL Test MULTI_MEASUREMENTS left "+MULTI_MEASUREMENTS.get()+
- ", processed "+devicesProcessed.size()+"/"+waitForDevices.size());
- BTUtils.println(System.err, "****** WaitForDevices "+Arrays.toString(waitForDevices.toArray()));
- BTUtils.println(System.err, "****** DevicesProcessed "+Arrays.toString(devicesProcessed.toArray()));
+ ", processed "+BTDeviceRegistry.getDeviceProcessedCount()+"/"+BTDeviceRegistry.getWaitForDevicesCount());
+ BTDeviceRegistry.printWaitForDevices(System.err, "****** WaitForDevices ");
+ BTDeviceRegistry.printDevicesProcessed(System.err, "****** DevicesProcessed ");
done = true;
} else {
try {
@@ -836,46 +778,37 @@ public class DBTScanner10 {
test.SHOW_UPDATE_EVENTS = true;
} else if( arg.equals("-quiet") ) {
test.QUIET = true;
- } else if( arg.equals("-scanActive") ) {
- le_scan_active = true;
+ } else if( arg.equals("-scanPassive") ) {
+ le_scan_active = false;
} else if( arg.equals("-shutdown") && args.length > (i+1) ) {
test.shutdownTest = Integer.valueOf(args[++i]).intValue();
- } else if( arg.equals("-mac") && args.length > (i+1) ) {
- final BDAddressAndType a = new BDAddressAndType(new EUI48(args[++i]), BDAddressType.BDADDR_UNDEFINED);
- test.waitForDevices.add(a);
+ } else if( arg.equals("-dev") && args.length > (i+1) ) {
+ BTDeviceRegistry.addToWaitForDevices( args[++i] );
} else if( arg.equals("-wl") && args.length > (i+1) ) {
final BDAddressAndType wle = new BDAddressAndType(new EUI48(args[++i]), BDAddressType.BDADDR_LE_PUBLIC);
BTUtils.println(System.err, "Whitelist + "+wle);
test.whitelist.add(wle);
test.USE_WHITELIST = true;
- } else if( arg.equals("-passkey") && args.length > (i+3) ) {
- final String mac = args[++i];
- final byte atype = (byte) ( Integer.valueOf(args[++i]).intValue() & 0xff );
- final BDAddressAndType macAndType = new BDAddressAndType(new EUI48(mac), BDAddressType.get(atype));
- final MyBTSecurityDetail sec = MyBTSecurityDetail.getOrCreate(macAndType);
+ } else if( arg.equals("-passkey") && args.length > (i+2) ) {
+ final String addrOrNameSub = args[++i];
+ final BTSecurityRegistry.Entry sec = BTSecurityRegistry.getOrCreate(addrOrNameSub);
sec.passkey = Integer.valueOf(args[++i]).intValue();
System.err.println("Set passkey in "+sec);
- } else if( arg.equals("-seclevel") && args.length > (i+3) ) {
- final String mac = args[++i];
- final byte atype = (byte) ( Integer.valueOf(args[++i]).intValue() & 0xff );
- final BDAddressAndType macAndType = new BDAddressAndType(new EUI48(mac), BDAddressType.get(atype));
- final MyBTSecurityDetail sec = MyBTSecurityDetail.getOrCreate(macAndType);
+ } else if( arg.equals("-seclevel") && args.length > (i+2) ) {
+ final String addrOrNameSub = args[++i];
+ final BTSecurityRegistry.Entry sec = BTSecurityRegistry.getOrCreate(addrOrNameSub);
final int sec_level_i = Integer.valueOf(args[++i]).intValue();
sec.sec_level = BTSecurityLevel.get( (byte)( sec_level_i & 0xff ) );
System.err.println("Set sec_level "+sec_level_i+" in "+sec);
- } else if( arg.equals("-iocap") && args.length > (i+3) ) {
- final String mac = args[++i];
- final byte atype = (byte) ( Integer.valueOf(args[++i]).intValue() & 0xff );
- final BDAddressAndType macAndType = new BDAddressAndType(new EUI48(mac), BDAddressType.get(atype));
- final MyBTSecurityDetail sec = MyBTSecurityDetail.getOrCreate(macAndType);
+ } else if( arg.equals("-iocap") && args.length > (i+2) ) {
+ final String addrOrNameSub = args[++i];
+ final BTSecurityRegistry.Entry sec = BTSecurityRegistry.getOrCreate(addrOrNameSub);
final int io_cap_i = Integer.valueOf(args[++i]).intValue();
sec.io_cap = SMPIOCapability.get( (byte)( io_cap_i & 0xff ) );
System.err.println("Set io_cap "+io_cap_i+" in "+sec);
- } else if( arg.equals("-secauto") && args.length > (i+3) ) {
- final String mac = args[++i];
- final byte atype = (byte) ( Integer.valueOf(args[++i]).intValue() & 0xff );
- final BDAddressAndType macAndType = new BDAddressAndType(new EUI48(mac), BDAddressType.get(atype));
- final MyBTSecurityDetail sec = MyBTSecurityDetail.getOrCreate(macAndType);
+ } else if( arg.equals("-secauto") && args.length > (i+2) ) {
+ final String addrOrNameSub = args[++i];
+ final BTSecurityRegistry.Entry sec = BTSecurityRegistry.getOrCreate(addrOrNameSub);
final int io_cap_i = Integer.valueOf(args[++i]).intValue();
sec.io_cap_auto = SMPIOCapability.get( (byte)( io_cap_i & 0xff ) );
System.err.println("Set SEC AUTO security io_cap "+io_cap_i+" in "+sec);
@@ -900,13 +833,13 @@ public class DBTScanner10 {
BTUtils.println(System.err, "Run with '[-btmode LE|BREDR|DUAL] "+
"[-bluetoothManager <BluetoothManager-Implementation-Class-Name>] "+
"[-disconnect] [-enableGATTPing] [-count <number>] [-single] [-show_update_events] [-quiet] "+
- "[-scanActive]"+
+ "[-scanPassive]"+
"[-resetEachCon connectionCount] "+
- "(-mac <device_address>)* (-wl <device_address>)* "+
- "[-seclevel <device_address> <(int)address_type> <int>] "+
- "[-iocap <device_address> <(int)address_type> <int>] "+
- "[-secauto <device_address> <(int)address_type> <int>] "+
- "[-passkey <device_address> <(int)address_type> <digits>] " +
+ "(-dev <device_[address|name]_sub>)* (-wl <device_address>)* "+
+ "(-seclevel <device_[address|name]_sub> <int_sec_level>)* "+
+ "(-iocap <device_[address|name]_sub> <int_iocap>)* "+
+ "(-secauto <device_[address|name]_sub> <int_iocap>)* "+
+ "(-passkey <device_[address|name]_sub> <digits>)* "+
"[-charid <uuid>] [-charval <byte-val>] "+
"[-verbose] [-debug] "+
"[-dbt_verbose true|false] "+
@@ -929,9 +862,9 @@ public class DBTScanner10 {
BTUtils.println(System.err, "characteristic-id: "+test.charIdentifier);
BTUtils.println(System.err, "characteristic-value: "+test.charValue);
- BTUtils.println(System.err, "security-details: "+MyBTSecurityDetail.allToString() );
+ BTUtils.println(System.err, "security-details: "+BTSecurityRegistry.allToString() );
- BTUtils.println(System.err, "waitForDevice: "+Arrays.toString(test.waitForDevices.toArray()));
+ BTDeviceRegistry.printWaitForDevices(System.err, "waitForDevices: ");
if( waitForEnter ) {
BTUtils.println(System.err, "Press ENTER to continue\n");
diff --git a/java/org/direct_bt/BTDeviceRegistry.java b/java/org/direct_bt/BTDeviceRegistry.java
new file mode 100644
index 00000000..c9779b4f
--- /dev/null
+++ b/java/org/direct_bt/BTDeviceRegistry.java
@@ -0,0 +1,165 @@
+/**
+ * Author: Sven Gothel <[email protected]>
+ * Copyright (c) 2020 Gothel Software e.K.
+ * Copyright (c) 2020 ZAFENA AB
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.direct_bt;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Application toolkit providing BT device registration of processed and awaited devices.
+ * The latter on a pattern matching basis, i.e. EUI48Sub or name-sub.
+ */
+public class BTDeviceRegistry {
+ private static class DeviceQuery {
+ public final EUI48Sub addressSub;
+ public final String nameSub;
+ public DeviceQuery(final EUI48Sub as, final String ns) {
+ addressSub = as;
+ nameSub = ns;
+ }
+ @Override
+ public String toString() {
+ if( addressSub.length>0 ) {
+ return addressSub.toString();
+ } else {
+ return "'"+nameSub+"'";
+ }
+ }
+ };
+ private static List<DeviceQuery> waitForDevices = new ArrayList<DeviceQuery>();
+
+ private static class DeviceID {
+ public final BDAddressAndType addressAndType;
+ public final String name;
+ public DeviceID(final BDAddressAndType a, final String n) {
+ addressAndType = a;
+ name = n;
+ }
+ @Override
+ public String toString() {
+ return "["+addressAndType+", "+name+"]";
+ }
+ };
+ private static Collection<DeviceID> devicesInProcessing = Collections.synchronizedCollection(new ArrayList<>());
+ private static Collection<DeviceID> devicesProcessed = Collections.synchronizedCollection(new ArrayList<>());
+
+ public static void addToWaitForDevices(final String addrOrNameSub) {
+ final EUI48Sub addr1 = new EUI48Sub();
+ final StringBuilder errmsg = new StringBuilder();
+ if( EUI48Sub.scanEUI48Sub(addrOrNameSub, addr1, errmsg) ) {
+ waitForDevices.add( new DeviceQuery( addr1, "" ) );
+ } else {
+ addr1.clear();
+ waitForDevices.add( new DeviceQuery( addr1, addrOrNameSub ) );
+ }
+ }
+ public static boolean isWaitingForDevice(final BDAddressAndType mac, final String name) {
+ for(final Iterator<DeviceQuery> it=waitForDevices.iterator(); it.hasNext(); ) {
+ final DeviceQuery q = it.next();
+ if( ( q.addressSub.length>0 && mac.address.contains(q.addressSub) ) ||
+ ( q.nameSub.length()>0 && name.indexOf(q.nameSub) >= 0 ) ) {
+ return true;
+ }
+ }
+ return false;
+ }
+ public static boolean isWaitingForAnyDevice() {
+ return waitForDevices.size()>0;
+ }
+ public static int getWaitForDevicesCount() {
+ return waitForDevices.size();
+ }
+ public static void printWaitForDevices(final PrintStream out, final String msg) {
+ BTUtils.println(out, msg+" "+Arrays.toString(waitForDevices.toArray()));
+ }
+
+ public static void addToDevicesProcessed(final BDAddressAndType a, final String n) {
+ devicesProcessed.add( new DeviceID(a, n) );
+ }
+ public static boolean isDeviceProcessed(final BDAddressAndType a) {
+ for(final Iterator<DeviceID> it=devicesProcessed.iterator(); it.hasNext(); ) {
+ final DeviceID id = it.next();
+ if( id.addressAndType.equals(a) ) {
+ return true;
+ }
+ }
+ return false;
+ }
+ public static int getDeviceProcessedCount() {
+ return devicesProcessed.size();
+ }
+ public static boolean allDevicesProcessed() {
+ for(final Iterator<DeviceQuery> it1=waitForDevices.iterator(); it1.hasNext(); ) {
+ final DeviceQuery q = it1.next();
+ final Iterator<DeviceID> it2=devicesProcessed.iterator();
+ while( it2.hasNext() ) {
+ final DeviceID id = it2.next();
+ if( ( q.addressSub.length>0 && id.addressAndType.address.contains(q.addressSub) ) ||
+ ( q.nameSub.length()>0 && id.name.indexOf(q.nameSub) >= 0 ) ) {
+ break;
+ }
+ }
+ if( !it2.hasNext() ) {
+ return false;
+ }
+ }
+ return true;
+ }
+ public static void printDevicesProcessed(final PrintStream out, final String msg) {
+ BTUtils.println(out, msg+" "+Arrays.toString(devicesProcessed.toArray()));
+ }
+
+ public static void addToDevicesProcessing(final BDAddressAndType a, final String n) {
+ devicesInProcessing.add( new DeviceID(a, n) );
+ }
+ public static boolean removeFromDevicesProcessing(final BDAddressAndType a) {
+ for(final Iterator<DeviceID> it=devicesInProcessing.iterator(); it.hasNext(); ) {
+ final DeviceID id = it.next();
+ if ( id.addressAndType.equals(a) ) {
+ it.remove();
+ return true;
+ }
+ }
+ return false;
+ }
+ public static boolean isDeviceProcessing(final BDAddressAndType a) {
+ for(final Iterator<DeviceID> it=devicesInProcessing.iterator(); it.hasNext(); ) {
+ final DeviceID id = it.next();
+ if ( id.addressAndType.equals(a) ) {
+ return true;
+ }
+ }
+ return false;
+ }
+ public static int getDeviceProcessingCount() {
+ return devicesInProcessing.size();
+ }
+}
diff --git a/java/org/direct_bt/BTSecurityRegistry.java b/java/org/direct_bt/BTSecurityRegistry.java
new file mode 100644
index 00000000..adbf16e5
--- /dev/null
+++ b/java/org/direct_bt/BTSecurityRegistry.java
@@ -0,0 +1,141 @@
+/**
+ * Author: Sven Gothel <[email protected]>
+ * Copyright (c) 2020 Gothel Software e.K.
+ * Copyright (c) 2020 ZAFENA AB
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.direct_bt;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Application toolkit providing BT security setup and its device association
+ * on a pattern matching basis, i.e. EUI48Sub or name-sub.
+ */
+public class BTSecurityRegistry {
+ public static final int NO_PASSKEY = -1;
+
+ public static class Entry {
+ public EUI48Sub addrSub;
+ public String nameSub;
+
+ public BTSecurityLevel sec_level = BTSecurityLevel.UNSET;
+ public SMPIOCapability io_cap = SMPIOCapability.UNSET;
+ public SMPIOCapability io_cap_auto = SMPIOCapability.UNSET;
+ public int passkey = NO_PASSKEY;
+
+ public Entry(final EUI48Sub addrSub) {
+ this.addrSub = addrSub;
+ this.nameSub = "";
+ }
+ public Entry(final String nameSub) {
+ this.addrSub = EUI48Sub.ALL_DEVICE;
+ this.nameSub = nameSub;
+ }
+
+ public boolean matches(final EUI48Sub addressSub) {
+ return addrSub.length > 0 && addressSub.contains(addrSub);
+ }
+ public boolean matches(final EUI48 address) {
+ return addrSub.length > 0 && address.contains(addrSub);
+ }
+ public boolean matches(final String name) {
+ return nameSub.length() > 0 && name.indexOf(nameSub) >= 0;
+ }
+
+ public boolean isSecLevelOrIOCapSet() {
+ return SMPIOCapability.UNSET != io_cap || BTSecurityLevel.UNSET != sec_level;
+ }
+ public BTSecurityLevel getSecLevel() { return sec_level; }
+ public SMPIOCapability getIOCap() { return io_cap; }
+
+ public boolean isSecurityAutoEnabled() { return SMPIOCapability.UNSET != io_cap_auto; }
+ public SMPIOCapability getSecurityAutoIOCap() { return io_cap_auto; }
+
+ public int getPairingPasskey() { return passkey; }
+
+ public boolean getPairingNumericComparison() { return true; }
+
+ @Override
+ public String toString() {
+ final String id = EUI48Sub.ALL_DEVICE.equals(addrSub) ? "'"+nameSub+"'" : addrSub.toString();
+ return "BTSecurityDetail["+id+", lvl "+sec_level+", io "+io_cap+", auto-io "+io_cap_auto+", passkey "+passkey+"]";
+ }
+ }
+
+ static private List<BTSecurityRegistry.Entry> devicesSecDetails = new ArrayList<BTSecurityRegistry.Entry>();
+
+ public static BTSecurityRegistry.Entry get(final EUI48 addr) {
+ for(final Iterator<BTSecurityRegistry.Entry> i=devicesSecDetails.iterator(); i.hasNext(); ) {
+ final BTSecurityRegistry.Entry sd = i.next();
+ if( sd.matches(addr) ) {
+ return sd;
+ }
+ }
+ return null;
+ }
+ public static BTSecurityRegistry.Entry get(final EUI48Sub addrSub) {
+ for(final Iterator<BTSecurityRegistry.Entry> i=devicesSecDetails.iterator(); i.hasNext(); ) {
+ final BTSecurityRegistry.Entry sd = i.next();
+ if( sd.matches(addrSub) ) {
+ return sd;
+ }
+ }
+ return null;
+ }
+ public static BTSecurityRegistry.Entry get(final String nameSub) {
+ for(final Iterator<BTSecurityRegistry.Entry> i=devicesSecDetails.iterator(); i.hasNext(); ) {
+ final BTSecurityRegistry.Entry sd = i.next();
+ if( sd.matches(nameSub) ) {
+ return sd;
+ }
+ }
+ return null;
+ }
+
+ public static BTSecurityRegistry.Entry getOrCreate(final String addrOrNameSub) {
+ final EUI48Sub addr1 = new EUI48Sub();
+ final StringBuilder errmsg = new StringBuilder();
+ BTSecurityRegistry.Entry sec = null;
+ if( EUI48Sub.scanEUI48Sub(addrOrNameSub, addr1, errmsg) ) {
+ sec = get(addr1);
+ if( null == sec ) {
+ sec = new BTSecurityRegistry.Entry( addr1 );
+ devicesSecDetails.add(sec);
+ }
+ } else {
+ sec = get(addrOrNameSub);
+ if( null == sec ) {
+ sec = new BTSecurityRegistry.Entry( addrOrNameSub );
+ devicesSecDetails.add(sec);
+ }
+ }
+ return sec;
+ }
+
+ public static String allToString() {
+ return Arrays.toString( devicesSecDetails.toArray() );
+ }
+}
diff --git a/scripts/run-dbt_scanner10.sh b/scripts/run-dbt_scanner10.sh
index e88e46f1..cb7f57b7 100755
--- a/scripts/run-dbt_scanner10.sh
+++ b/scripts/run-dbt_scanner10.sh
@@ -13,16 +13,22 @@
# ../scripts/run-dbt_scanner10.sh
#
# Read device C0:26:DA:01:DA:B1 (using default auto-sec w/ keyboard iocap)
-# ../scripts/run-dbt_scanner10.sh -mac C0:26:DA:01:DA:B1
+# ../scripts/run-dbt_scanner10.sh -dev C0:26:DA:01:DA:B1
#
# Read device C0:26:DA:01:DA:B1 (enforcing no security)
-# ../scripts/run-dbt_scanner10.sh -mac C0:26:DA:01:DA:B1 -seclevel C0:26:DA:01:DA:B1 1 1
+# ../scripts/run-dbt_scanner10.sh -dev C0:26:DA:01:DA:B1 -seclevel C0:26:DA:01:DA:B1 1
+#
+# Read any device containing C0:26:DA (enforcing no security)
+# ../scripts/run-dbt_scanner10.sh -dev C0:26:DA -seclevel C0:26:DA 1
+#
+# Read any device containing name 'TAIDOC' (enforcing no security)
+# ../scripts/run-dbt_scanner10.sh -dev 'TAIDOC' -seclevel 'TAIDOC' 1
#
# Read device C0:26:DA:01:DA:B1, basic debug flags enabled (using default auto-sec w/ keyboard iocap)
-# ../scripts/run-dbt_scanner10.sh -mac C0:26:DA:01:DA:B1 -dbt_debug true
+# ../scripts/run-dbt_scanner10.sh -dev C0:26:DA:01:DA:B1 -dbt_debug true
#
# Read device C0:26:DA:01:DA:B1, all debug flags enabled (using default auto-sec w/ keyboard iocap)
-# ../scripts/run-dbt_scanner10.sh -mac C0:26:DA:01:DA:B1 -dbt_debug adapter.event,gatt.data,hci.event,hci.scan_ad_eir,mgmt.event
+# ../scripts/run-dbt_scanner10.sh -dev C0:26:DA:01:DA:B1 -dbt_debug adapter.event,gatt.data,hci.event,hci.scan_ad_eir,mgmt.event
#
# To do a BT adapter removal/add via software, assuming the device is '1-4' (Bus 1.Port 4):
# echo '1-4' > /sys/bus/usb/drivers/usb/unbind
diff --git a/src/direct_bt/BTDeviceRegistry.cpp b/src/direct_bt/BTDeviceRegistry.cpp
new file mode 100644
index 00000000..3d0262a1
--- /dev/null
+++ b/src/direct_bt/BTDeviceRegistry.cpp
@@ -0,0 +1,174 @@
+/*
+ * Author: Sven Gothel <[email protected]>
+ * Copyright (c) 2020 Gothel Software e.K.
+ * Copyright (c) 2020 ZAFENA AB
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "BTDeviceRegistry.hpp"
+
+#include <jau/cpp_lang_util.hpp>
+#include <jau/basic_algos.hpp>
+#include <jau/darray.hpp>
+
+using namespace direct_bt;
+
+namespace direct_bt::BTDeviceRegistry {
+ struct DeviceQuery {
+ EUI48Sub addressSub;
+ std::string nameSub;
+ DeviceQuery(const EUI48Sub& as, const std::string& ns) : addressSub(as), nameSub(ns) {}
+ DeviceQuery() : addressSub(), nameSub() {}
+ std::string toString() const {
+ if( addressSub.length>0 ) {
+ return addressSub.toString();
+ } else {
+ return "'"+nameSub+"'";
+ }
+ }
+ };
+ static jau::darray<DeviceQuery> waitForDevices;
+
+ struct DeviceID {
+ BDAddressAndType addressAndType;
+ std::string name;
+ DeviceID(const BDAddressAndType& a, const std::string& n) : addressAndType(a), name(n) {}
+ DeviceID() : addressAndType(), name() {}
+ std::string toString() const {
+ return "["+addressAndType.toString()+", '"+name+"']";
+ }
+ };
+ static jau::darray<DeviceID> devicesInProcessing;
+ static std::recursive_mutex mtx_devicesProcessing;
+
+ static jau::darray<DeviceID> devicesProcessed;
+ static std::recursive_mutex mtx_devicesProcessed;
+
+ void addToWaitForDevices(const std::string& addrOrNameSub) {
+ EUI48Sub addr1;
+ std::string errmsg;
+ if( EUI48Sub::scanEUI48Sub(addrOrNameSub, addr1, errmsg) ) {
+ waitForDevices.emplace_back( addr1, "" );
+ } else {
+ addr1.clear();
+ waitForDevices.emplace_back( addr1, addrOrNameSub );
+ }
+ }
+ bool isWaitingForDevice(const BDAddressAndType &mac, const std::string &name) {
+ return waitForDevices.cend() != jau::find_if(waitForDevices.cbegin(), waitForDevices.cend(), [&](const DeviceQuery & it)->bool {
+ return ( it.addressSub.length>0 && mac.address.contains(it.addressSub) ) ||
+ ( it.nameSub.length()>0 && name.find(it.nameSub) != std::string::npos );
+ });
+ }
+ bool isWaitingForAnyDevice() {
+ return !waitForDevices.empty();
+ }
+ size_t getWaitForDevicesCount() {
+ return waitForDevices.size();
+ }
+ static void printList(FILE *out, const std::string &msg, jau::darray<DeviceQuery> &cont) {
+ jau::fprintf_td(out, "%s ", msg.c_str());
+ jau::for_each(cont.cbegin(), cont.cend(), [out](const DeviceQuery& q) {
+ fprintf(out, "%s, ", q.toString().c_str());
+ });
+ fprintf(out, "\n");
+ }
+ void printWaitForDevices(FILE *out, const std::string &msg) {
+ printList(out, msg, waitForDevices);
+ }
+
+ void addToDevicesProcessed(const BDAddressAndType &a, const std::string& n) {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessed); // RAII-style acquire and relinquish via destructor
+ devicesProcessed.emplace_back(a, n);
+ }
+ bool isDeviceProcessed(const BDAddressAndType & a) {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessed); // RAII-style acquire and relinquish via destructor
+ for (auto it = devicesProcessed.cbegin(); it != devicesProcessed.cend(); ++it) {
+ if( it->addressAndType == a ) {
+ return true;
+ }
+ }
+ return false;
+ }
+ size_t getDeviceProcessedCount() {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessed); // RAII-style acquire and relinquish via destructor
+ return devicesProcessed.size();
+ }
+ bool allDevicesProcessed() {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessed); // RAII-style acquire and relinquish via destructor
+ for (auto it1 = waitForDevices.cbegin(); it1 != waitForDevices.cend(); ++it1) {
+ const DeviceQuery& q = *it1;
+ auto it2 = devicesProcessed.cbegin();
+ while ( it2 != devicesProcessed.cend() ) {
+ const DeviceID& id = *it2;
+ if( ( q.addressSub.length>0 && id.addressAndType.address.contains(q.addressSub) ) ||
+ ( q.nameSub.length()>0 && id.name.find(q.nameSub) != std::string::npos ) ) {
+ break;
+ }
+ ++it2;
+ }
+ if( it2 == devicesProcessed.cend() ) {
+ return false;
+ }
+ }
+ return true;
+ }
+ static void printList(FILE *out, const std::string &msg, jau::darray<DeviceID> &cont) {
+ jau::fprintf_td(out, "%s ", msg.c_str());
+ jau::for_each(cont.cbegin(), cont.cend(), [out](const DeviceID &id) {
+ fprintf(out, "%s, ", id.toString().c_str());
+ });
+ fprintf(out, "\n");
+ }
+ void printDevicesProcessed(FILE *out, const std::string &msg) {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessed); // RAII-style acquire and relinquish via destructor
+ printList(out, msg, devicesProcessed);
+ }
+
+ void addToDevicesProcessing(const BDAddressAndType &a, const std::string& n) {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessing); // RAII-style acquire and relinquish via destructor
+ devicesInProcessing.emplace_back(a, n);
+ }
+ bool removeFromDevicesProcessing(const BDAddressAndType &a) {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessing); // RAII-style acquire and relinquish via destructor
+ for (auto it = devicesInProcessing.begin(); it != devicesInProcessing.end(); ++it) {
+ if ( it->addressAndType == a ) {
+ devicesInProcessing.erase(it);
+ return true;
+ }
+ }
+ return false;
+ }
+ bool isDeviceProcessing(const BDAddressAndType & a) {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessing); // RAII-style acquire and relinquish via destructor
+ for (auto it = devicesInProcessing.cbegin(); it != devicesInProcessing.cend(); ++it) {
+ if( it->addressAndType == a ) {
+ return true;
+ }
+ }
+ return false;
+ }
+ size_t getDeviceProcessingCount() {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessing); // RAII-style acquire and relinquish via destructor
+ return devicesInProcessing.size();
+ }
+
+} // namespace direct_bt::BTDeviceRegistry
diff --git a/src/direct_bt/BTSecurityRegistry.cpp b/src/direct_bt/BTSecurityRegistry.cpp
new file mode 100644
index 00000000..fae1756f
--- /dev/null
+++ b/src/direct_bt/BTSecurityRegistry.cpp
@@ -0,0 +1,98 @@
+/*
+ * Author: Sven Gothel <[email protected]>
+ * Copyright (c) 2020 Gothel Software e.K.
+ * Copyright (c) 2020 ZAFENA AB
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <BTSecurityRegistry.hpp>
+
+#include <jau/darray.hpp>
+
+using namespace direct_bt;
+
+namespace direct_bt::BTSecurityRegistry {
+
+ static jau::darray<Entry> devicesSecDetails;
+
+ Entry* get(const EUI48& addr) {
+ auto first = devicesSecDetails.begin();
+ auto last = devicesSecDetails.end();
+ for (; first != last; ++first) {
+ if ( first->matches(addr) ) {
+ return &(*first);
+ }
+ }
+ return nullptr;
+ }
+ Entry* get(const EUI48Sub& addrSub) {
+ auto first = devicesSecDetails.begin();
+ auto last = devicesSecDetails.end();
+ for (; first != last; ++first) {
+ if ( first->matches(addrSub) ) {
+ return &(*first);
+ }
+ }
+ return nullptr;
+ }
+ Entry* get(const std::string& nameSub) {
+ auto first = devicesSecDetails.begin();
+ auto last = devicesSecDetails.end();
+ for (; first != last; ++first) {
+ if ( first->matches(nameSub) ) {
+ return &(*first);
+ }
+ }
+ return nullptr;
+ }
+ Entry* getOrCreate(const std::string& addrOrNameSub) {
+ EUI48Sub addr1;
+ std::string errmsg;
+ Entry* sec = nullptr;
+ if( EUI48Sub::scanEUI48Sub(addrOrNameSub, addr1, errmsg) ) {
+ sec = get(addr1);
+ if( nullptr == sec ) {
+ Entry& r = devicesSecDetails.emplace_back( addr1 );
+ sec = &r;
+ }
+ } else {
+ sec = get(addrOrNameSub);
+ if( nullptr == sec ) {
+ Entry& r = devicesSecDetails.emplace_back( addrOrNameSub );
+ sec = &r;
+ }
+ }
+ return sec;
+ }
+ std::string allToString() {
+ std::string res;
+ int i=0;
+ for(auto iter = devicesSecDetails.cbegin(); iter != devicesSecDetails.cend(); ++iter, ++i) {
+ const Entry& sec = *iter;
+ if( 0 < i ) {
+ res += ", ";
+ }
+ res += sec.toString();
+ }
+ return res;
+ }
+
+} // namespace direct_bt::BTSecurityRegistry
diff --git a/src/direct_bt/CMakeLists.txt b/src/direct_bt/CMakeLists.txt
index dea50003..8fba441a 100644
--- a/src/direct_bt/CMakeLists.txt
+++ b/src/direct_bt/CMakeLists.txt
@@ -19,11 +19,13 @@ set (direct_bt_LIB_SRCS
${PROJECT_SOURCE_DIR}/src/direct_bt/ATTPDUTypes.cpp
${PROJECT_SOURCE_DIR}/src/direct_bt/BTAdapter.cpp
${PROJECT_SOURCE_DIR}/src/direct_bt/BTDevice.cpp
+ ${PROJECT_SOURCE_DIR}/src/direct_bt/BTDeviceRegistry.cpp
${PROJECT_SOURCE_DIR}/src/direct_bt/BTGattDesc.cpp
${PROJECT_SOURCE_DIR}/src/direct_bt/BTGattChar.cpp
${PROJECT_SOURCE_DIR}/src/direct_bt/BTGattService.cpp
${PROJECT_SOURCE_DIR}/src/direct_bt/BTGattHandler.cpp
${PROJECT_SOURCE_DIR}/src/direct_bt/BTManager.cpp
+ ${PROJECT_SOURCE_DIR}/src/direct_bt/BTSecurityRegistry.cpp
${PROJECT_SOURCE_DIR}/src/direct_bt/BTTypes0.cpp
${PROJECT_SOURCE_DIR}/src/direct_bt/BTTypes1.cpp
${PROJECT_SOURCE_DIR}/src/direct_bt/GATTNumbers.cpp