aboutsummaryrefslogtreecommitdiffstats
path: root/src/direct_bt
diff options
context:
space:
mode:
Diffstat (limited to 'src/direct_bt')
-rw-r--r--src/direct_bt/DBTAdapter.cpp1
-rw-r--r--src/direct_bt/DBTDevice.cpp62
-rw-r--r--src/direct_bt/DBTManager.cpp21
-rw-r--r--src/direct_bt/GATTHandler.cpp39
-rw-r--r--src/direct_bt/HCIComm.cpp27
-rw-r--r--src/direct_bt/L2CAPComm.cpp5
6 files changed, 90 insertions, 65 deletions
diff --git a/src/direct_bt/DBTAdapter.cpp b/src/direct_bt/DBTAdapter.cpp
index 47465254..308d4be6 100644
--- a/src/direct_bt/DBTAdapter.cpp
+++ b/src/direct_bt/DBTAdapter.cpp
@@ -557,6 +557,7 @@ bool DBTAdapter::mgmtEvDeviceConnectedCB(std::shared_ptr<MgmtEvent> e) {
if( 0 < new_connect ) {
addConnectedDevice(device); // track it
}
+ device->notifyConnected();
int i=0;
for_each_idx_mtx(mtx_statusListenerList, statusListenerList, [&](std::shared_ptr<AdapterStatusListener> &l) {
try {
diff --git a/src/direct_bt/DBTDevice.cpp b/src/direct_bt/DBTDevice.cpp
index 8146d3cb..fdf242e9 100644
--- a/src/direct_bt/DBTDevice.cpp
+++ b/src/direct_bt/DBTDevice.cpp
@@ -45,6 +45,7 @@ using namespace direct_bt;
DBTDevice::DBTDevice(DBTAdapter & a, EInfoReport const & r)
: adapter(a), ts_creation(r.getTimestamp()), address(r.getAddress()), addressType(r.getAddressType())
{
+ isConnected = false;
if( !r.isSet(EIRDataType::BDADDR) ) {
throw IllegalArgumentException("DBTDevice ctor: Address not set: "+r.toString(), E_FILE_LINE);
}
@@ -119,7 +120,8 @@ std::string DBTDevice::toString(bool includeDiscoveredServices) const {
const uint64_t t0 = getCurrentMilliseconds();
std::string msdstr = nullptr != msd ? msd->toString() : "MSD[null]";
std::string out("Device[address["+getAddressString()+", "+getBDAddressTypeString(getAddressType())+"], name['"+name+
- "'], age "+std::to_string(t0-ts_creation)+" ms, lup "+std::to_string(t0-ts_update)+" ms, rssi "+std::to_string(getRSSI())+
+ "'], age "+std::to_string(t0-ts_creation)+" ms, lup "+std::to_string(t0-ts_update)+
+ " ms, connected "+std::to_string(isConnected)+", rssi "+std::to_string(getRSSI())+
", tx-power "+std::to_string(tx_power)+
", appearance "+uint16HexString(static_cast<uint16_t>(appearance))+" ("+AppearanceCatToString(appearance)+
"), "+msdstr+", "+javaObjectToString()+"]");
@@ -339,40 +341,66 @@ uint16_t DBTDevice::connectDefault()
}
}
+void DBTDevice::notifyConnected() {
+ DBG_PRINT("DBTDevice::notifyConnected: %s", toString().c_str());
+ isConnected = true;
+}
+
void DBTDevice::notifyDisconnected() {
- DBG_PRINT("DBTDevice::notifyDisconnected: disconnecting ...");
- disconnect(false); // coming from manager disconnect, but ensure cleaning up!
+ DBG_PRINT("DBTDevice::notifyDisconnected: %s", toString().c_str());
+ try {
+ // coming from manager disconnect, ensure cleaning up!
+ disconnect(true /* sentFromManager */, false /* ioErrorCause */);
+ } catch (std::exception &e) {
+ ERR_PRINT("Exception caught on %s: %s", toString().c_str(), e.what());
+ }
+ isConnected = false;
}
-void DBTDevice::disconnect(const bool disconnectManager, const uint8_t reason) {
- DBG_PRINT("DBTDevice::disconnect: disconnectManager %d, gattHandler %d, hciConnHandle %d",
- disconnectManager, (nullptr != gattHandler), (0 != hciConnHandle));
+void DBTDevice::disconnect(const bool sentFromManager, const bool ioErrorCause, const uint8_t reason) {
+ DBG_PRINT("DBTDevice::disconnect: isConnected %d, sentFromManager %d, ioError %d, gattHandler %d, hciConnHandle %d",
+ isConnected.load(), sentFromManager, ioErrorCause, (nullptr != gattHandler), (0 != hciConnHandle));
disconnectGATT();
const std::lock_guard<std::recursive_mutex> lock(adapter.mtx_hci); // RAII-style acquire and relinquish via destructor
std::shared_ptr<HCIComm> hciComm = adapter.getHCI();
+ if( !isConnected ) {
+ DBG_PRINT("DBTDevice::disconnect: Skip disconnect: Not connected: %s", toString().c_str());
+ goto exit;
+ }
+ isConnected = false;
+
+ if( ioErrorCause ) {
+ DBG_PRINT("DBTDevice::disconnect: Skip HCI disconnect: IO Error: %s", toString().c_str());
+ goto skip_hci_disconnect;
+ }
+
if( 0 == hciConnHandle ) {
- DBG_PRINT("DBTDevice::disconnect: HCI not connected");
+ DBG_PRINT("DBTDevice::disconnect: Skip HCI disconnect: HCI not connected: %s", toString().c_str());
goto skip_hci_disconnect;
}
if( nullptr == hciComm || !hciComm->isOpen() ) {
- DBG_PRINT("DBTDevice::disconnect: Adapter's HCIComm not open: %s", toString().c_str());
- } else {
- if( !hciComm->disconnect(hciConnHandle, reason) ) {
- DBG_PRINT("DBTDevice::disconnect: handle 0x%X, errno %d %s", hciConnHandle, errno, strerror(errno));
- }
+ DBG_PRINT("DBTDevice::disconnect: Skip HCI disconnect: HCI not Open: %s", toString().c_str());
+ goto skip_hci_disconnect;
+ }
+
+ if( !hciComm->disconnect(hciConnHandle, reason) ) {
+ DBG_PRINT("DBTDevice::disconnect: handle 0x%X, errno %d %s", hciConnHandle, errno, strerror(errno));
}
- hciConnHandle = 0;
skip_hci_disconnect:
- if( disconnectManager ) {
+ hciConnHandle = 0;
+
+ if( !sentFromManager ) {
// Also issue mngr.disconnect on non-HCI connect (whitelist),
// which will also send the DISCONNECT event.
DBTManager & mngr = adapter.getManager();
- mngr.disconnect(adapter.dev_id, address, addressType, reason);
+ mngr.disconnect(ioErrorCause, adapter.dev_id, address, addressType, reason);
}
+
+exit:
adapter.removeConnectedDevice(*this);
}
@@ -381,7 +409,7 @@ void DBTDevice::remove() {
releaseSharedInstance();
}
-std::shared_ptr<GATTHandler> DBTDevice::connectGATT(int timeoutMS) {
+std::shared_ptr<GATTHandler> DBTDevice::connectGATT(int replyTimeoutMS) {
std::shared_ptr<DBTDevice> sharedInstance = getSharedInstance();
if( nullptr == sharedInstance ) {
throw InternalError("DBTDevice::connectGATT: Device unknown to adapter and not tracked: "+toString(), E_FILE_LINE);
@@ -394,7 +422,7 @@ std::shared_ptr<GATTHandler> DBTDevice::connectGATT(int timeoutMS) {
}
gattHandler = nullptr;
}
- gattHandler = std::shared_ptr<GATTHandler>(new GATTHandler(sharedInstance, timeoutMS));
+ gattHandler = std::shared_ptr<GATTHandler>(new GATTHandler(sharedInstance, replyTimeoutMS));
if( !gattHandler->connect() ) {
DBG_PRINT("DBTDevice::connectGATT: Connection failed");
gattHandler = nullptr;
diff --git a/src/direct_bt/DBTManager.cpp b/src/direct_bt/DBTManager.cpp
index 5f38b9a4..b8ac12fa 100644
--- a/src/direct_bt/DBTManager.cpp
+++ b/src/direct_bt/DBTManager.cpp
@@ -165,7 +165,7 @@ std::shared_ptr<MgmtEvent> DBTManager::sendWithReply(MgmtCommand &req) {
// Ringbuffer read is thread safe
int retry = 3;
while( 0 < retry ) {
- std::shared_ptr<MgmtEvent> res = mgmtEventRing.getBlocking(MGMT_READER_THREAD_POLL_TIMEOUT);
+ std::shared_ptr<MgmtEvent> res = mgmtEventRing.getBlocking(MGMT_COMMAND_REPLY_TIMEOUT);
// std::shared_ptr<MgmtEvent> res = receiveNext();
if( nullptr == res ) {
errno = ETIMEDOUT;
@@ -607,14 +607,19 @@ uint16_t DBTManager::create_connection(const int dev_id,
return 0;
}
-bool DBTManager::disconnect(const int dev_id, const EUI48 &peer_bdaddr, const BDAddressType peer_mac_type, const uint8_t reason) {
- MgmtDisconnectCmd req(dev_id, peer_bdaddr, peer_mac_type);
- std::shared_ptr<MgmtEvent> res = sendWithReply(req);
+bool DBTManager::disconnect(const bool ioErrorCause,
+ const int dev_id, const EUI48 &peer_bdaddr, const BDAddressType peer_mac_type,
+ const uint8_t reason) {
bool bres = false;
- if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
- const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get());
- if( MgmtStatus::SUCCESS == res1.getStatus() ) {
- bres = true;
+
+ if( !ioErrorCause ) {
+ MgmtDisconnectCmd req(dev_id, peer_bdaddr, peer_mac_type);
+ std::shared_ptr<MgmtEvent> res = sendWithReply(req);
+ if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
+ const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get());
+ if( MgmtStatus::SUCCESS == res1.getStatus() ) {
+ bres = true;
+ }
}
}
// explicit disconnected event anyways
diff --git a/src/direct_bt/GATTHandler.cpp b/src/direct_bt/GATTHandler.cpp
index 81a03ef8..61256a13 100644
--- a/src/direct_bt/GATTHandler.cpp
+++ b/src/direct_bt/GATTHandler.cpp
@@ -60,6 +60,7 @@ extern "C" {
#include "GATTHandler.hpp"
+#include "HCIComm.hpp"
#include "DBTTypes.hpp"
#include "DBTDevice.hpp"
@@ -97,7 +98,7 @@ GATTHandler::State GATTHandler::validateState() {
// ", l2cap[open "+std::to_string(b)+", state "+l2cap->getStateString()+"]", E_FILE_LINE);
ERR_PRINT("Inconsistent open state: GattHandler[open %d, %s], l2cap[open [%d, %d], state %s]: %s",
a, getStateString().c_str(), b, c, l2cap.getStateString().c_str(), deviceString.c_str());
- disconnect(); // state -> Disconnected
+ disconnect(true /* ioErrorCause */); // state -> Disconnected
}
}
return state;
@@ -169,6 +170,7 @@ bool GATTHandler::getSendIndicationConfirmation() {
}
void GATTHandler::l2capReaderThreadImpl() {
+ bool ioErrorCause = false;
l2capReaderShallStop = false;
l2capReaderRunning = true;
INFO_PRINT("l2capReaderThreadImpl Started");
@@ -182,7 +184,7 @@ void GATTHandler::l2capReaderThreadImpl() {
break;
}
- len = l2cap.read(rbuffer.get_wptr(), rbuffer.getSize(), timeoutMS);
+ len = l2cap.read(rbuffer.get_wptr(), rbuffer.getSize(), L2CAP_READER_THREAD_POLL_TIMEOUT);
if( 0 < len ) {
const AttPDUMsg * attPDU = AttPDUMsg::getSpecialized(rbuffer.get_ptr(), len);
const AttPDUMsg::Opcode opc = attPDU->getOpcode();
@@ -247,17 +249,18 @@ void GATTHandler::l2capReaderThreadImpl() {
} else if( ETIMEDOUT != errno && !l2capReaderShallStop ) { // expected exits
ERR_PRINT("GATTHandler::l2capReaderThread: l2cap read error -> Stop");
l2capReaderShallStop = true;
+ ioErrorCause = true;
}
}
INFO_PRINT("l2capReaderThreadImpl Ended");
l2capReaderRunning = false;
- disconnect();
+ disconnect(ioErrorCause);
}
-GATTHandler::GATTHandler(const std::shared_ptr<DBTDevice> &device, const int timeoutMS)
+GATTHandler::GATTHandler(const std::shared_ptr<DBTDevice> &device, const int replyTimeoutMS)
: device(device), deviceString(device->getAddressString()), rbuffer(ClientMaxMTU),
- l2cap(device, L2CAP_PSM_UNDEF, L2CAP_CID_ATT), timeoutMS(timeoutMS),
+ l2cap(device, L2CAP_PSM_UNDEF, L2CAP_CID_ATT), replyTimeoutMS(replyTimeoutMS),
state(Disconnected), attPDURing(ATTPDU_RING_CAPACITY),
l2capReaderThreadId(0), l2capReaderRunning(false), l2capReaderShallStop(false),
serverMTU(DEFAULT_MIN_ATT_MTU), usedMTU(DEFAULT_MIN_ATT_MTU)
@@ -265,7 +268,7 @@ GATTHandler::GATTHandler(const std::shared_ptr<DBTDevice> &device, const int tim
GATTHandler::~GATTHandler() {
eventListenerList.clear();
- disconnect();
+ disconnect(false /* ioErrorCause */);
}
bool GATTHandler::connect() {
@@ -295,13 +298,13 @@ bool GATTHandler::connect() {
usedMTU = std::min((int)ClientMaxMTU, (int)serverMTU);
if( 0 == serverMTU ) {
ERR_PRINT("GATTHandler::connect: Zero serverMTU -> disconnect: %s", deviceString.c_str());
- disconnect();
+ disconnect(false /* ioErrorCause */);
return false;
}
return true;
}
-bool GATTHandler::disconnect() {
+bool GATTHandler::disconnect(const bool ioErrorCause) {
DBG_PRINT("GATTHandler::disconnect: GattHandler[%s], l2cap[%s], connected %d, device-value %d",
getStateString().c_str(), l2cap.getStateString().c_str(),
(Disconnected < state), (nullptr != device));
@@ -321,7 +324,10 @@ bool GATTHandler::disconnect() {
if( l2capReaderRunning ) {
l2capReaderShallStop = true;
if( !is_l2capReader && 0 != tid_l2capReader ) {
- pthread_kill(tid_l2capReader, SIGALRM);
+ int kerr;
+ if( 0 != ( kerr = pthread_kill(tid_l2capReader, SIGALRM) ) ) {
+ ERR_PRINT("GATTHandler::disconnect: pthread_kill %p FAILED: %d", (void*)tid_l2capReader, kerr);
+ }
}
}
@@ -329,7 +335,12 @@ bool GATTHandler::disconnect() {
state = Disconnected;
if( nullptr != device ) {
- device->disconnect(); // cleanup device resources, proper connection state
+ // Cleanup device resources, proper connection state
+ // Intentionally giving the POWER_OFF reason for the device in case of ioErrorCause!
+ const uint8_t reason = ioErrorCause ?
+ static_cast<uint8_t>(HCIErrorCode::REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF) :
+ static_cast<uint8_t>(HCIErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+ device->disconnect(false /* sentFromManager */, ioErrorCause, reason);
}
DBG_PRINT("GATTHandler::disconnect End");
@@ -353,14 +364,14 @@ void GATTHandler::send(const AttPDUMsg & msg) {
if( 0 > res ) {
ERR_PRINT("GATTHandler::send: l2cap write error -> disconnect: %s to %s", msg.toString().c_str(), deviceString.c_str());
state = Error;
- disconnect(); // state -> Disconnected
+ disconnect(true /* ioErrorCause */); // state -> Disconnected
throw BluetoothException("GATTHandler::send: l2cap write error: req "+msg.toString()+" to "+deviceString, E_FILE_LINE);
}
if( res != msg.pdu.getSize() ) {
ERR_PRINT("GATTHandler::send: l2cap write count error, %d != %d: %s -> disconnect: %s",
res, msg.pdu.getSize(), msg.toString().c_str(), deviceString.c_str());
state = Error;
- disconnect(); // state -> Disconnected
+ disconnect(true /* ioErrorCause */); // state -> Disconnected
throw BluetoothException("GATTHandler::send: l2cap write count error, "+std::to_string(res)+" != "+std::to_string(res)
+": "+msg.toString()+" -> disconnect: "+deviceString, E_FILE_LINE);
}
@@ -374,14 +385,14 @@ std::shared_ptr<const AttPDUMsg> GATTHandler::sendWithReply(const AttPDUMsg & ms
if( nullptr == res ) {
errno = ETIMEDOUT;
ERR_PRINT("GATTHandler::send: nullptr result (timeout): req %s to %s", msg.toString().c_str(), deviceString.c_str());
- disconnect();
+ disconnect(true /* ioErrorCause */);
throw BluetoothException("GATTHandler::send: nullptr result (timeout): req "+msg.toString()+" to "+deviceString, E_FILE_LINE);
}
return res;
}
std::shared_ptr<const AttPDUMsg> GATTHandler::receiveNext() {
- return attPDURing.getBlocking(timeoutMS);
+ return attPDURing.getBlocking(replyTimeoutMS);
}
uint16_t GATTHandler::exchangeMTU(const uint16_t clientMaxMTU) {
diff --git a/src/direct_bt/HCIComm.cpp b/src/direct_bt/HCIComm.cpp
index d82bba5e..0a2b2618 100644
--- a/src/direct_bt/HCIComm.cpp
+++ b/src/direct_bt/HCIComm.cpp
@@ -370,7 +370,7 @@ HCIErrorCode HCIComm::send_req(const uint16_t opcode, const void *command, const
#else
while ((n = poll(&p, 1, _timeoutMS)) < 0) {
#endif
- ERR_PRINT("hci_send_req: poll");
+ ERR_PRINT("HCIComm::send_req(dev_id %d, channel %d): poll: res %d", dev_id, channel, n);
if (errno == EAGAIN || errno == EINTR) {
continue;
}
@@ -392,7 +392,7 @@ HCIErrorCode HCIComm::send_req(const uint16_t opcode, const void *command, const
int len;
while ((len = ::read(_dd, buf, sizeof(buf))) < 0) {
- ERR_PRINT("hci_send_req: read: res %d", len);
+ ERR_PRINT("HCIComm::send_req(dev_id %d, channel %d): read: res %d", dev_id, channel, len);
if (errno == EAGAIN || errno == EINTR) {
continue;
}
@@ -456,29 +456,6 @@ HCIErrorCode HCIComm::send_req(const uint16_t opcode, const void *command, const
rlen, bytesHexString((uint8_t*)ptr, 0, rlen, false /* lsbFirst */, true /* leading0X */).c_str());
goto done;
}
- case HCI_EV_REMOTE_NAME: {
- DBG_PRINT("hci_send_req: HCI_EV_REMOTE_NAME: event 0x%X (equal %d), exp_event 0x%X, r-len %d/%d",
- hdr->evt, exp_event, (hdr->evt == exp_event), response_len, len);
-
- if (hdr->evt != exp_event) {
- continue; // next packet
- }
-
- const hci_ev_remote_name *rn = static_cast<const hci_ev_remote_name *>(static_cast<const void *>( ptr ));
- const hci_cp_remote_name_req *cp = static_cast<const hci_cp_remote_name_req *>(command);
-
- if ( rn->bdaddr != cp->bdaddr ) {
- DBG_PRINT("hci_send_req: HCI_EV_REMOTE_NAME: address mismatch: cmd %s != req %s",
- cp->bdaddr.toString().c_str(), rn->bdaddr.toString().c_str());
- continue; // next packet
- }
-
- const int rlen = MIN(len, response_len);
- memcpy(response, ptr, rlen);
- DBG_PRINT("hci_send_req: HCI_EV_REMOTE_NAME: copied %d bytes: %s",
- rlen, bytesHexString((uint8_t*)ptr, 0, rlen, false /* lsbFirst */, true /* leading0X */).c_str());
- goto done;
- }
case HCI_EV_LE_META: {
const hci_ev_le_meta *me = static_cast<const hci_ev_le_meta *>(static_cast<const void *>( ptr ));
diff --git a/src/direct_bt/L2CAPComm.cpp b/src/direct_bt/L2CAPComm.cpp
index b58ee536..c36bedb8 100644
--- a/src/direct_bt/L2CAPComm.cpp
+++ b/src/direct_bt/L2CAPComm.cpp
@@ -192,7 +192,10 @@ bool L2CAPComm::disconnect() {
if( 0 != _tid_connect ) {
pthread_t tid_self = pthread_self();
if( tid_self != _tid_connect ) {
- pthread_kill(_tid_connect, SIGALRM);
+ int kerr;
+ if( 0 != ( kerr = pthread_kill(_tid_connect, SIGALRM) ) ) {
+ ERR_PRINT("L2CAP::disconnect: pthread_kill %p FAILED: %d", (void*)_tid_connect, kerr);
+ }
}
}