37 #include <sys/socket.h>
51 #include "L2CAPIoctl.hpp"
60 SMPEnv::SMPEnv() noexcept
61 : exploding(
jau::environment::getExplodingProperties("
direct_bt.smp") ),
62 SMP_READ_COMMAND_REPLY_TIMEOUT(
jau::environment::getInt32Property("
direct_bt.smp.cmd.read.timeout", 500, 250 , INT32_MAX ) ),
63 SMP_WRITE_COMMAND_REPLY_TIMEOUT(
jau::environment::getInt32Property("
direct_bt.smp.cmd.write.timeout", 500, 250 , INT32_MAX ) ),
64 SMPPDU_RING_CAPACITY(
jau::environment::getInt32Property("
direct_bt.smp.ringsize", 128, 64 , 1024 ) ),
65 DEBUG_DATA(
jau::environment::getBooleanProperty("
direct_bt.debug.smp.data", false) )
69 #if SMP_SUPPORTED_BY_OS
76 std::shared_ptr<BTDevice> ref = wbr_device.lock();
77 if(
nullptr == ref ) {
83 bool SMPHandler::validateConnected() noexcept {
84 bool l2capIsConnected = l2cap.
isOpen();
87 if( has_ioerror || l2capHasIOError ) {
89 ERR_PRINT(
"IOError state: GattHandler %s, l2cap %s: %s",
94 if( !is_connected || !l2capIsConnected ) {
95 ERR_PRINT(
"Disconnected state: GattHandler %s, l2cap %s: %s",
102 void SMPHandler::l2capReaderThreadImpl() {
104 const std::lock_guard<std::mutex> lock(mtx_l2capReaderLifecycle);
105 l2capReaderShallStop =
false;
106 l2capReaderRunning =
true;
108 cv_l2capReaderInit.notify_all();
111 DBG_PRINT(
"SMPHandler::l2capReaderThreadCleanup: l2capReaderRunning %d -> 0", l2capReaderRunning.
load());
112 l2capReaderRunning =
false;
115 while( !l2capReaderShallStop ) {
117 if( !validateConnected() ) {
118 ERR_PRINT(
"SMPHandler::reader: Invalid IO state -> Stop");
119 l2capReaderShallStop =
true;
135 if( smpPDURing.isFull() ) {
137 smpPDURing.drop(dropCount);
138 WARN_PRINT(
"SMPHandler-IO RECV Drop (%u oldest elements of %u capacity, ring full)", dropCount, smpPDURing.capacity());
140 smpPDURing.putBlocking( std::move(smpPDU) );
142 }
else if( ETIMEDOUT != errno && !l2capReaderShallStop ) {
143 IRQ_PRINT(
"SMPHandler::reader: l2cap read error -> Stop; l2cap.read %d", len);
144 l2capReaderShallStop =
true;
149 const std::lock_guard<std::mutex> lock(mtx_l2capReaderLifecycle);
150 WORDY_PRINT(
"SMPHandler::reader: Ended. Ring has %u entries flushed", smpPDURing.getSize());
152 l2capReaderRunning =
false;
153 cv_l2capReaderInit.notify_all();
160 wbr_device(device), deviceString(device->getAddressAndType().toString()), rbuffer(
number(Defaults::SMP_MTU_BUFFER_SZ)),
162 is_connected(l2cap.open(*device)), has_ioerror(
false),
163 smpPDURing(
nullptr, env.SMPPDU_RING_CAPACITY), l2capReaderShallStop(
false),
164 l2capReaderThreadId(0), l2capReaderRunning(
false),
165 mtu(
number(Defaults::MIN_SMP_MTU))
167 if( !validateConnected() ) {
168 ERR_PRINT(
"SMPHandler.ctor: L2CAP could not connect");
169 is_connected =
false;
172 DBG_PRINT(
"SMPHandler::ctor: Start Connect: GattHandler[%s], l2cap[%s]: %s",
173 getStateString().c_str(), l2cap.getStateString().c_str(), deviceString.c_str());
180 std::unique_lock<std::mutex> lock(mtx_l2capReaderLifecycle);
182 std::thread l2capReaderThread(&SMPHandler::l2capReaderThreadImpl,
this);
183 l2capReaderThreadId = l2capReaderThread.native_handle();
186 l2capReaderThread.detach();
188 while(
false == l2capReaderRunning ) {
189 cv_l2capReaderInit.wait(lock);
194 uint16_t mtu_ =
number(Defaults::MIN_SMP_MTU);
195 mtu = std::min(
number(Defaults::LE_SECURE_SMP_MTU), (
int)mtu_);
218 if( !is_connected.compare_exchange_strong(expConn,
false) ) {
220 DBG_PRINT(
"SMPHandler::disconnect: Not connected: disconnectDevice %d, ioErrorCause %d: GattHandler[%s], l2cap[%s]: %s",
221 disconnectDevice, ioErrorCause, getStateString().c_str(), l2cap.getStateString().c_str(), deviceString.c_str());
226 const std::lock_guard<std::recursive_mutex> lock(mtx_command);
227 DBG_PRINT(
"SMPHandler::disconnect: Start: disconnectDevice %d, ioErrorCause %d: GattHandler[%s], l2cap[%s]: %s",
228 disconnectDevice, ioErrorCause, getStateString().c_str(), l2cap.getStateString().c_str(), deviceString.c_str());
233 std::unique_lock<std::mutex> lockReader(mtx_l2capReaderLifecycle);
236 const pthread_t tid_self = pthread_self();
237 const pthread_t tid_l2capReader = l2capReaderThreadId;
238 l2capReaderThreadId = 0;
239 const bool is_l2capReader = tid_l2capReader == tid_self;
240 DBG_PRINT(
"SMPHandler.disconnect: l2capReader[running %d, shallStop %d, isReader %d, tid %p)",
241 l2capReaderRunning.load(), l2capReaderShallStop.load(), is_l2capReader, (
void*)tid_l2capReader);
242 if( l2capReaderRunning ) {
243 l2capReaderShallStop =
true;
244 if( !is_l2capReader && 0 != tid_l2capReader ) {
246 if( 0 != ( kerr = pthread_kill(tid_l2capReader, SIGALRM) ) ) {
247 ERR_PRINT(
"SMPHandler::disconnect: pthread_kill %p FAILED: %d", (
void*)tid_l2capReader, kerr);
251 while(
true == l2capReaderRunning ) {
252 cv_l2capReaderInit.wait(lockReader);
258 if( disconnectDevice ) {
259 std::shared_ptr<BTDevice> device = getDeviceUnchecked();
260 if(
nullptr != device ) {
271 DBG_PRINT(
"SMPHandler::disconnect: End: %s", deviceString.c_str());
275 void SMPHandler::send(
const SMPPDUMsg & msg) {
276 if( !validateConnected() ) {
287 IRQ_PRINT(
"SMPHandler::send: l2cap write error -> disconnect: %s to %s", msg.
toString().c_str(), deviceString.c_str());
292 if(
static_cast<size_t>(res) != msg.
pdu.
getSize() ) {
293 ERR_PRINT(
"SMPHandler::send: l2cap write count error, %zd != %zu: %s -> disconnect: %s",
302 std::unique_ptr<const SMPPDUMsg> SMPHandler::sendWithReply(
const SMPPDUMsg & msg,
const int timeout) {
306 std::unique_ptr<const SMPPDUMsg> res = smpPDURing.getBlocking(timeout);
307 if(
nullptr == res ) {
309 IRQ_PRINT(
"SMPHandler::sendWithReply: nullptr result (timeout %d): req %s to %s", timeout, msg.
toString().c_str(), deviceString.c_str());
332 void SMPHandler::clearAllCallbacks() noexcept {
333 smpSecurityReqCallbackList.
clear();