diff --git a/src/platform/Linux/BLEManagerImpl.cpp b/src/platform/Linux/BLEManagerImpl.cpp index 4e4e853ccdc69f..bf0f4eb2f909bd 100644 --- a/src/platform/Linux/BLEManagerImpl.cpp +++ b/src/platform/Linux/BLEManagerImpl.cpp @@ -344,21 +344,26 @@ void BLEManagerImpl::HandlePlatformSpecificBLEEvent(const ChipDeviceEvent * apEv uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const { - BluezConnection * connection = static_cast(conId); - return (connection != nullptr) ? connection->mMtu : 0; + uint16_t mtu = 0; + VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED, + ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__)); + mtu = conId->GetMTU(); +exit: + return mtu; } bool BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) { bool result = false; + VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED, + ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__)); VerifyOrExit(Ble::UUIDsMatch(svcId, &CHIP_BLE_SVC_ID), ChipLogError(DeviceLayer, "SubscribeCharacteristic() called with invalid service ID")); VerifyOrExit(Ble::UUIDsMatch(charId, &ChipUUID_CHIPoBLEChar_TX), ChipLogError(DeviceLayer, "SubscribeCharacteristic() called with invalid characteristic ID")); - VerifyOrExit(BluezSubscribeCharacteristic(conId) == CHIP_NO_ERROR, - ChipLogError(DeviceLayer, "BluezSubscribeCharacteristic() failed")); + VerifyOrExit(conId->SubscribeCharacteristic() == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "SubscribeCharacteristic() failed")); result = true; exit: @@ -369,13 +374,15 @@ bool BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, cons { bool result = false; + VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED, + ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__)); VerifyOrExit(Ble::UUIDsMatch(svcId, &CHIP_BLE_SVC_ID), ChipLogError(DeviceLayer, "UnsubscribeCharacteristic() called with invalid service ID")); VerifyOrExit(Ble::UUIDsMatch(charId, &ChipUUID_CHIPoBLEChar_TX), ChipLogError(DeviceLayer, "UnsubscribeCharacteristic() called with invalid characteristic ID")); - VerifyOrExit(BluezUnsubscribeCharacteristic(conId) == CHIP_NO_ERROR, - ChipLogError(DeviceLayer, "BluezUnsubscribeCharacteristic() failed")); + VerifyOrExit(conId->UnsubscribeCharacteristic() == CHIP_NO_ERROR, + ChipLogError(DeviceLayer, "UnsubscribeCharacteristic() failed")); result = true; exit: @@ -386,9 +393,11 @@ bool BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId) { bool result = false; + VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED, + ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__)); ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (con %p)", conId); - VerifyOrExit(CloseBluezConnection(conId) == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "CloseBluezConnection() failed")); + VerifyOrExit(conId->CloseConnection() == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "CloseConnection() failed")); result = true; exit: @@ -400,8 +409,9 @@ bool BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUU { bool result = false; - VerifyOrExit(SendBluezIndication(conId, std::move(pBuf)) == CHIP_NO_ERROR, - ChipLogError(DeviceLayer, "SendBluezIndication() failed")); + VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED, + ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__)); + VerifyOrExit(conId->SendIndication(std::move(pBuf)) == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "SendIndication() failed")); result = true; exit: @@ -413,13 +423,14 @@ bool BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const Ble::Ch { bool result = false; + VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED, + ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__)); VerifyOrExit(Ble::UUIDsMatch(svcId, &CHIP_BLE_SVC_ID), ChipLogError(DeviceLayer, "SendWriteRequest() called with invalid service ID")); VerifyOrExit(Ble::UUIDsMatch(charId, &ChipUUID_CHIPoBLEChar_RX), ChipLogError(DeviceLayer, "SendWriteRequest() called with invalid characteristic ID")); - VerifyOrExit(BluezSendWriteRequest(conId, std::move(pBuf)) == CHIP_NO_ERROR, - ChipLogError(DeviceLayer, "BluezSendWriteRequest() failed")); + VerifyOrExit(conId->SendWriteRequest(std::move(pBuf)) == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "SendWriteRequest() failed")); result = true; exit: @@ -541,30 +552,18 @@ void BLEManagerImpl::CHIPoBluez_ConnectionClosed(BLE_CONNECTION_OBJECT conId) void BLEManagerImpl::HandleTXCharCCCDWrite(BLE_CONNECTION_OBJECT conId) { - CHIP_ERROR err = CHIP_NO_ERROR; - - BluezConnection * connection = static_cast(conId); - - VerifyOrExit(connection != nullptr, ChipLogError(DeviceLayer, "Connection is NULL in HandleTXCharCCCDWrite")); - VerifyOrExit(connection->mpC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in HandleTXCharCCCDWrite")); + VerifyOrReturn(conId != BLE_CONNECTION_UNINITIALIZED, + ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__)); // Post an event to the Chip queue to process either a CHIPoBLE Subscribe or Unsubscribe based on // whether the client is enabling or disabling indications. - { - ChipDeviceEvent event; - event.Type = connection->mIsNotify ? DeviceEventType::kCHIPoBLESubscribe : DeviceEventType::kCHIPoBLEUnsubscribe; - event.CHIPoBLESubscribe.ConId = connection; - PlatformMgr().PostEventOrDie(&event); - } - - ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", connection->mIsNotify ? "subscribe" : "unsubscribe"); + ChipDeviceEvent event; + event.Type = conId->IsNotifyAcquired() ? DeviceEventType::kCHIPoBLESubscribe : DeviceEventType::kCHIPoBLEUnsubscribe; + event.CHIPoBLESubscribe.ConId = conId; + PlatformMgr().PostEventOrDie(&event); -exit: - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "HandleTXCharCCCDWrite() failed: %s", ErrorStr(err)); - // TODO: fail connection - } + ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", + (event.Type == DeviceEventType::kCHIPoBLESubscribe) ? "subscribe" : "unsubscribe"); } void BLEManagerImpl::HandleTXComplete(BLE_CONNECTION_OBJECT conId) diff --git a/src/platform/Linux/BlePlatformConfig.h b/src/platform/Linux/BlePlatformConfig.h index 4c1ffd4e66420a..54640b707ab720 100644 --- a/src/platform/Linux/BlePlatformConfig.h +++ b/src/platform/Linux/BlePlatformConfig.h @@ -27,13 +27,15 @@ namespace chip { namespace DeviceLayer { namespace Internal { -struct BluezConnection; +class BluezConnection; } // namespace Internal } // namespace DeviceLayer } // namespace chip // ==================== Platform Adaptations ==================== +#define BLE_CONNECTION_OBJECT chip::DeviceLayer::Internal::BluezConnection * #define BLE_CONNECTION_UNINITIALIZED nullptr + // ========== Platform-specific Configuration Overrides ========= /* none so far */ diff --git a/src/platform/Linux/bluez/BluezConnection.cpp b/src/platform/Linux/bluez/BluezConnection.cpp index 142df8f1317202..2d4286a4fe6069 100644 --- a/src/platform/Linux/bluez/BluezConnection.cpp +++ b/src/platform/Linux/bluez/BluezConnection.cpp @@ -40,130 +40,311 @@ namespace chip { namespace DeviceLayer { namespace Internal { -static CHIP_ERROR BluezC2Indicate(BluezConnection::ConnectionDataBundle * closure) +namespace { + +gboolean BluezIsServiceOnDevice(BluezGattService1 * aService, BluezDevice1 * aDevice) { - BluezConnection * conn = nullptr; - GAutoPtr error; - GIOStatus status; - const char * buf; - size_t len, written; + const auto * servicePath = bluez_gatt_service1_get_device(aService); + const auto * devicePath = g_dbus_proxy_get_object_path(G_DBUS_PROXY(aDevice)); + return strcmp(servicePath, devicePath) == 0 ? TRUE : FALSE; +} - VerifyOrExit(closure != nullptr, ChipLogError(DeviceLayer, "ConnectionDataBundle is NULL in %s", __func__)); +gboolean BluezIsCharOnService(BluezGattCharacteristic1 * aChar, BluezGattService1 * aService) +{ + const auto * charPath = bluez_gatt_characteristic1_get_service(aChar); + const auto * servicePath = g_dbus_proxy_get_object_path(G_DBUS_PROXY(aService)); + ChipLogDetail(DeviceLayer, "Char %s on service %s", charPath, servicePath); + return strcmp(charPath, servicePath) == 0 ? TRUE : FALSE; +} - conn = closure->mpConn; - VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__)); - VerifyOrExit(conn->mpC2 != nullptr, ChipLogError(DeviceLayer, "FAIL: C2 Indicate: %s", "NULL C2")); +} // namespace - if (bluez_gatt_characteristic1_get_notify_acquired(conn->mpC2) == TRUE) - { - buf = (char *) g_variant_get_fixed_array(closure->mpVal, &len, sizeof(uint8_t)); - VerifyOrExit(len <= static_cast(std::numeric_limits::max()), - ChipLogError(DeviceLayer, "FAIL: buffer too large in %s", __func__)); - status = g_io_channel_write_chars(conn->mC2Channel.mpChannel, buf, static_cast(len), &written, - &MakeUniquePointerReceiver(error).Get()); - g_variant_unref(closure->mpVal); - closure->mpVal = nullptr; +BluezConnection::BluezConnection(BluezEndpoint * apEndpoint, BluezDevice1 * apDevice) : + mpEndpoint(apEndpoint), mpDevice(BLUEZ_DEVICE1(g_object_ref(apDevice))) +{ + Init(); +} - VerifyOrExit(status == G_IO_STATUS_NORMAL, ChipLogError(DeviceLayer, "FAIL: C2 Indicate: %s", error->message)); +BluezConnection::~BluezConnection() +{ + g_object_unref(mpDevice); + if (mpService) + g_object_unref(mpService); + if (mpC1) + g_object_unref(mpC1); + if (mpC2) + g_object_unref(mpC2); +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + if (mpC3) + g_object_unref(mpC2); +#endif +} + +BluezConnection::IOChannel::~IOChannel() +{ + if (mWatchSource != nullptr) + // Make sure the source is detached before destroying the channel. + g_source_destroy(mWatchSource.get()); +} + +BluezConnection::ConnectionDataBundle::ConnectionDataBundle(const BluezConnection & aConn, + const chip::System::PacketBufferHandle & aBuf) : + mConn(aConn), + mData(g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, aBuf->Start(), aBuf->DataLength(), sizeof(uint8_t))) +{} + +CHIP_ERROR BluezConnection::Init() +{ + // populate the service and the characteristics + GList * objects = nullptr; + GList * l; + + if (!mpEndpoint->mIsCentral) + { + mpService = BLUEZ_GATT_SERVICE1(g_object_ref(mpEndpoint->mpService)); + mpC1 = BLUEZ_GATT_CHARACTERISTIC1(g_object_ref(mpEndpoint->mpC1)); + mpC2 = BLUEZ_GATT_CHARACTERISTIC1(g_object_ref(mpEndpoint->mpC2)); } else { - bluez_gatt_characteristic1_set_value(conn->mpC2, closure->mpVal); - closure->mpVal = nullptr; + objects = g_dbus_object_manager_get_objects(mpEndpoint->mpObjMgr); + + for (l = objects; l != nullptr; l = l->next) + { + BluezObject * object = BLUEZ_OBJECT(l->data); + BluezGattService1 * service = bluez_object_get_gatt_service1(object); + + if (service != nullptr) + { + if ((BluezIsServiceOnDevice(service, mpDevice)) == TRUE && + (strcmp(bluez_gatt_service1_get_uuid(service), CHIP_BLE_UUID_SERVICE_STRING) == 0)) + { + mpService = service; + break; + } + g_object_unref(service); + } + } + + VerifyOrExit(mpService != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL service in %s", __func__)); + + for (l = objects; l != nullptr; l = l->next) + { + BluezObject * object = BLUEZ_OBJECT(l->data); + BluezGattCharacteristic1 * char1 = bluez_object_get_gatt_characteristic1(object); + + if (char1 != nullptr) + { + if ((BluezIsCharOnService(char1, mpService) == TRUE) && + (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C1_STRING) == 0)) + { + mpC1 = char1; + } + else if ((BluezIsCharOnService(char1, mpService) == TRUE) && + (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C2_STRING) == 0)) + { + mpC2 = char1; + } +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + else if ((BluezIsCharOnService(char1, mpService) == TRUE) && + (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C3_STRING) == 0)) + { + mpC3 = char1; + } +#endif + else + { + g_object_unref(char1); + } + if ((mpC1 != nullptr) && (mpC2 != nullptr)) + { + break; + } + } + } + + VerifyOrExit(mpC1 != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL C1 in %s", __func__)); + VerifyOrExit(mpC2 != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL C2 in %s", __func__)); } exit: - if (closure != nullptr) - { - g_free(closure); - } + if (objects != nullptr) + g_list_free_full(objects, g_object_unref); + return CHIP_NO_ERROR; +} +CHIP_ERROR BluezConnection::BluezDisconnect(BluezConnection * conn) +{ + GAutoPtr error; + gboolean success; + + ChipLogDetail(DeviceLayer, "%s peer=%s", __func__, conn->GetPeerAddress()); + + success = bluez_device1_call_disconnect_sync(conn->mpDevice, nullptr, &MakeUniquePointerReceiver(error).Get()); + VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", error->message)); + +exit: return CHIP_NO_ERROR; } -static BluezConnection::ConnectionDataBundle * MakeConnectionDataBundle(BLE_CONNECTION_OBJECT apConn, - const chip::System::PacketBufferHandle & apBuf) +CHIP_ERROR BluezConnection::CloseConnection() { - auto * bundle = g_new(BluezConnection::ConnectionDataBundle, 1); - bundle->mpConn = static_cast(apConn); - bundle->mpVal = - g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, apBuf->Start(), apBuf->DataLength() * sizeof(uint8_t), sizeof(uint8_t)); - return bundle; + return PlatformMgrImpl().GLibMatterContextInvokeSync(BluezDisconnect, this); } -CHIP_ERROR SendBluezIndication(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf) +const char * BluezConnection::GetPeerAddress() const { - VerifyOrReturnError(!apBuf.IsNull(), CHIP_ERROR_INVALID_ARGUMENT, ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__)); - return PlatformMgrImpl().GLibMatterContextInvokeSync(BluezC2Indicate, MakeConnectionDataBundle(apConn, apBuf)); + return bluez_device1_get_address(mpDevice); } -static CHIP_ERROR BluezDisconnect(BluezConnection * conn) +gboolean BluezConnection::WriteHandlerCallback(GIOChannel * aChannel, GIOCondition aCond, BluezConnection * apConn) { - GAutoPtr error; - gboolean success; + uint8_t buf[512 /* characteristic max size per BLE specification */]; + bool isSuccess = false; + GVariant * newVal; + ssize_t len; - VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "conn is NULL in %s", __func__)); - VerifyOrExit(conn->mpDevice != nullptr, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", "NULL Device")); + VerifyOrExit(!(aCond & G_IO_HUP), ChipLogError(DeviceLayer, "INFO: socket disconnected in %s", __func__)); + VerifyOrExit(!(aCond & (G_IO_ERR | G_IO_NVAL)), ChipLogError(DeviceLayer, "INFO: socket error in %s", __func__)); + VerifyOrExit(aCond == G_IO_IN, ChipLogError(DeviceLayer, "FAIL: error in %s", __func__)); - ChipLogDetail(DeviceLayer, "%s peer=%s", __func__, bluez_device1_get_address(conn->mpDevice)); + ChipLogDetail(DeviceLayer, "C1 %s MTU: %d", __func__, apConn->GetMTU()); - success = bluez_device1_call_disconnect_sync(conn->mpDevice, nullptr, &MakeUniquePointerReceiver(error).Get()); - VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", error->message)); + len = read(g_io_channel_unix_get_fd(aChannel), buf, sizeof(buf)); + VerifyOrExit(len > 0, ChipLogError(DeviceLayer, "FAIL: short read in %s (%zd)", __func__, len)); + + // Casting len to size_t is safe, since we ensured that it's not negative. + newVal = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, buf, static_cast(len), sizeof(uint8_t)); + + bluez_gatt_characteristic1_set_value(apConn->mpC1, newVal); + BLEManagerImpl::HandleRXCharWrite(apConn, buf, static_cast(len)); + isSuccess = true; + +exit: + return isSuccess ? G_SOURCE_CONTINUE : G_SOURCE_REMOVE; +} + +void BluezConnection::SetupWriteHandler(int aSocketFd) +{ + auto channel = g_io_channel_unix_new(aSocketFd); + g_io_channel_set_encoding(channel, nullptr, nullptr); + g_io_channel_set_close_on_unref(channel, TRUE); + g_io_channel_set_buffered(channel, FALSE); + + auto watchSource = g_io_create_watch(channel, static_cast(G_IO_HUP | G_IO_IN | G_IO_ERR | G_IO_NVAL)); + g_source_set_callback(watchSource, G_SOURCE_FUNC(WriteHandlerCallback), this, nullptr); + + mC1Channel.mChannel.reset(channel); + mC1Channel.mWatchSource.reset(watchSource); + + PlatformMgrImpl().GLibMatterContextAttachSource(watchSource); +} + +gboolean BluezConnection::NotifyHandlerCallback(GIOChannel *, GIOCondition, BluezConnection *) +{ + return G_SOURCE_REMOVE; +} + +void BluezConnection::SetupNotifyHandler(int aSocketFd, bool aAdditionalAdvertising) +{ + auto channel = g_io_channel_unix_new(aSocketFd); + g_io_channel_set_encoding(channel, nullptr, nullptr); + g_io_channel_set_close_on_unref(channel, TRUE); + g_io_channel_set_buffered(channel, FALSE); + + auto watchSource = g_io_create_watch(channel, static_cast(G_IO_HUP | G_IO_ERR | G_IO_NVAL)); + g_source_set_callback(watchSource, G_SOURCE_FUNC(NotifyHandlerCallback), this, nullptr); + +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + if (aAdditionalAdvertising) + { + mC3Channel.mChannel.reset(channel); + mC3Channel.mWatchSource.reset(watchSource); + } + else +#endif + { + mC2Channel.mChannel.reset(channel); + mC2Channel.mWatchSource.reset(watchSource); + } + + PlatformMgrImpl().GLibMatterContextAttachSource(watchSource); +} + +// SendIndication callbacks + +CHIP_ERROR BluezConnection::SendIndicationImpl(ConnectionDataBundle * data) +{ + GAutoPtr error; + size_t len, written; + + if (bluez_gatt_characteristic1_get_notify_acquired(data->mConn.mpC2) == TRUE) + { + auto * buf = static_cast(g_variant_get_fixed_array(data->mData.get(), &len, sizeof(uint8_t))); + VerifyOrExit(len <= static_cast(std::numeric_limits::max()), + ChipLogError(DeviceLayer, "FAIL: buffer too large in %s", __func__)); + auto status = g_io_channel_write_chars(data->mConn.mC2Channel.mChannel.get(), buf, static_cast(len), &written, + &MakeUniquePointerReceiver(error).Get()); + VerifyOrExit(status == G_IO_STATUS_NORMAL, ChipLogError(DeviceLayer, "FAIL: C2 Indicate: %s", error->message)); + } + else + { + bluez_gatt_characteristic1_set_value(data->mConn.mpC2, data->mData.release()); + } exit: return CHIP_NO_ERROR; } -CHIP_ERROR CloseBluezConnection(BLE_CONNECTION_OBJECT apConn) +CHIP_ERROR BluezConnection::SendIndication(chip::System::PacketBufferHandle apBuf) { - return PlatformMgrImpl().GLibMatterContextInvokeSync(BluezDisconnect, static_cast(apConn)); + VerifyOrReturnError(!apBuf.IsNull(), CHIP_ERROR_INVALID_ARGUMENT, ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__)); + VerifyOrReturnError(mpC2 != nullptr, CHIP_ERROR_INTERNAL, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__)); + + ConnectionDataBundle bundle(*this, apBuf); + return PlatformMgrImpl().GLibMatterContextInvokeSync(SendIndicationImpl, &bundle); } -// BluezSendWriteRequest callbacks +// SendWriteRequest callbacks -static void SendWriteRequestDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection) +void BluezConnection::SendWriteRequestDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection) { BluezGattCharacteristic1 * c1 = BLUEZ_GATT_CHARACTERISTIC1(aObject); GAutoPtr error; gboolean success = bluez_gatt_characteristic1_call_write_value_finish(c1, aResult, &MakeUniquePointerReceiver(error).Get()); - VerifyOrReturn(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezSendWriteRequest : %s", error->message)); - BLEManagerImpl::HandleWriteComplete(static_cast(apConnection)); + VerifyOrReturn(success == TRUE, ChipLogError(DeviceLayer, "FAIL: SendWriteRequest : %s", error->message)); + BLEManagerImpl::HandleWriteComplete(static_cast(apConnection)); } -static CHIP_ERROR SendWriteRequestImpl(BluezConnection::ConnectionDataBundle * data) +CHIP_ERROR BluezConnection::SendWriteRequestImpl(ConnectionDataBundle * data) { - GVariant * options = nullptr; GVariantBuilder optionsBuilder; - VerifyOrExit(data != nullptr, ChipLogError(DeviceLayer, "ConnectionDataBundle is NULL in %s", __func__)); - VerifyOrExit(data->mpConn != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__)); - VerifyOrExit(data->mpConn->mpC1 != nullptr, ChipLogError(DeviceLayer, "C1 is NULL in %s", __func__)); - g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE_ARRAY); g_variant_builder_add(&optionsBuilder, "{sv}", "type", g_variant_new_string("request")); - options = g_variant_builder_end(&optionsBuilder); + auto options = g_variant_builder_end(&optionsBuilder); - bluez_gatt_characteristic1_call_write_value(data->mpConn->mpC1, data->mpVal, options, nullptr, SendWriteRequestDone, - data->mpConn); + bluez_gatt_characteristic1_call_write_value(data->mConn.mpC1, data->mData.release(), options, nullptr, SendWriteRequestDone, + const_cast(&data->mConn)); -exit: - g_free(data); return CHIP_NO_ERROR; } -CHIP_ERROR BluezSendWriteRequest(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf) +CHIP_ERROR BluezConnection::SendWriteRequest(chip::System::PacketBufferHandle apBuf) { VerifyOrReturnError(!apBuf.IsNull(), CHIP_ERROR_INVALID_ARGUMENT, ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__)); - return PlatformMgrImpl().GLibMatterContextInvokeSync(SendWriteRequestImpl, MakeConnectionDataBundle(apConn, apBuf)); + VerifyOrReturnError(mpC1 != nullptr, CHIP_ERROR_INTERNAL, ChipLogError(DeviceLayer, "C1 is NULL in %s", __func__)); + + ConnectionDataBundle bundle(*this, apBuf); + return PlatformMgrImpl().GLibMatterContextInvokeSync(SendWriteRequestImpl, &bundle); } -// BluezSubscribeCharacteristic callbacks +// SubscribeCharacteristic callbacks -static void OnCharacteristicChanged(GDBusProxy * aInterface, GVariant * aChangedProperties, const gchar * const * aInvalidatedProps, - gpointer apConnection) +void BluezConnection::OnCharacteristicChanged(GDBusProxy * aInterface, GVariant * aChangedProperties, + const gchar * const * aInvalidatedProps, gpointer apConnection) { - BLE_CONNECTION_OBJECT connection = static_cast(apConnection); GAutoPtr dataValue(g_variant_lookup_value(aChangedProperties, "Value", G_VARIANT_TYPE_BYTESTRING)); VerifyOrReturn(dataValue != nullptr); @@ -171,24 +352,24 @@ static void OnCharacteristicChanged(GDBusProxy * aInterface, GVariant * aChanged auto buffer = g_variant_get_fixed_array(dataValue.get(), &bufferLen, sizeof(uint8_t)); VerifyOrReturn(buffer != nullptr, ChipLogError(DeviceLayer, "Characteristic value has unexpected type")); - BLEManagerImpl::HandleTXCharChanged(connection, static_cast(buffer), bufferLen); + BLEManagerImpl::HandleTXCharChanged(static_cast(apConnection), static_cast(buffer), + bufferLen); } -static void SubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection) +void BluezConnection::SubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection) { BluezGattCharacteristic1 * c2 = BLUEZ_GATT_CHARACTERISTIC1(aObject); GAutoPtr error; gboolean success = bluez_gatt_characteristic1_call_write_value_finish(c2, aResult, &MakeUniquePointerReceiver(error).Get()); - VerifyOrReturn(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezSubscribeCharacteristic : %s", error->message)); + VerifyOrReturn(success == TRUE, ChipLogError(DeviceLayer, "FAIL: SubscribeCharacteristic : %s", error->message)); - BLEManagerImpl::HandleSubscribeOpComplete(static_cast(apConnection), true); + BLEManagerImpl::HandleSubscribeOpComplete(static_cast(apConnection), true); } -static CHIP_ERROR SubscribeCharacteristicImpl(BluezConnection * connection) +CHIP_ERROR BluezConnection::SubscribeCharacteristicImpl(BluezConnection * connection) { BluezGattCharacteristic1 * c2 = nullptr; - VerifyOrExit(connection != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__)); VerifyOrExit(connection->mpC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__)); c2 = BLUEZ_GATT_CHARACTERISTIC1(connection->mpC2); @@ -200,29 +381,28 @@ static CHIP_ERROR SubscribeCharacteristicImpl(BluezConnection * connection) return CHIP_NO_ERROR; } -CHIP_ERROR BluezSubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn) +CHIP_ERROR BluezConnection::SubscribeCharacteristic() { - return PlatformMgrImpl().GLibMatterContextInvokeSync(SubscribeCharacteristicImpl, static_cast(apConn)); + return PlatformMgrImpl().GLibMatterContextInvokeSync(SubscribeCharacteristicImpl, this); } -// BluezUnsubscribeCharacteristic callbacks +// UnsubscribeCharacteristic callbacks -static void UnsubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection) +void BluezConnection::UnsubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection) { BluezGattCharacteristic1 * c2 = BLUEZ_GATT_CHARACTERISTIC1(aObject); GAutoPtr error; gboolean success = bluez_gatt_characteristic1_call_write_value_finish(c2, aResult, &MakeUniquePointerReceiver(error).Get()); - VerifyOrReturn(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezUnsubscribeCharacteristic : %s", error->message)); + VerifyOrReturn(success == TRUE, ChipLogError(DeviceLayer, "FAIL: UnsubscribeCharacteristic : %s", error->message)); // Stop listening to the TX characteristic changes g_signal_handlers_disconnect_by_data(c2, apConnection); - BLEManagerImpl::HandleSubscribeOpComplete(static_cast(apConnection), false); + BLEManagerImpl::HandleSubscribeOpComplete(static_cast(apConnection), false); } -static CHIP_ERROR UnsubscribeCharacteristicImpl(BluezConnection * connection) +CHIP_ERROR BluezConnection::UnsubscribeCharacteristicImpl(BluezConnection * connection) { - VerifyOrExit(connection != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__)); VerifyOrExit(connection->mpC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__)); bluez_gatt_characteristic1_call_stop_notify(connection->mpC2, nullptr, UnsubscribeCharacteristicDone, connection); @@ -231,9 +411,9 @@ static CHIP_ERROR UnsubscribeCharacteristicImpl(BluezConnection * connection) return CHIP_NO_ERROR; } -CHIP_ERROR BluezUnsubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn) +CHIP_ERROR BluezConnection::UnsubscribeCharacteristic() { - return PlatformMgrImpl().GLibMatterContextInvokeSync(UnsubscribeCharacteristicImpl, static_cast(apConn)); + return PlatformMgrImpl().GLibMatterContextInvokeSync(UnsubscribeCharacteristicImpl, this); } } // namespace Internal diff --git a/src/platform/Linux/bluez/BluezConnection.h b/src/platform/Linux/bluez/BluezConnection.h index 7375fbe79d915d..3a64ac931220a8 100644 --- a/src/platform/Linux/bluez/BluezConnection.h +++ b/src/platform/Linux/bluez/BluezConnection.h @@ -34,45 +34,104 @@ namespace Internal { struct BluezEndpoint; -struct BluezConnection +class BluezConnection { +public: + BluezConnection(BluezEndpoint * apEndpoint, BluezDevice1 * apDevice); + ~BluezConnection(); + const char * GetPeerAddress() const; + + uint16_t GetMTU() const { return mMtu; } + void SetMTU(uint16_t aMtu) { mMtu = aMtu; } + + bool IsNotifyAcquired() const { return mNotifyAcquired; } + void SetNotifyAcquired(bool aNotifyAcquired) { mNotifyAcquired = aNotifyAcquired; } + + /** + * @brief Setup callback for receiving data from the CHIP TX characteristic on + * the remote peripheral device. + * + * @note This function takes the ownership of the passed file descriptor and + * will close it when the connection is closed. + */ + void SetupWriteHandler(int aSocketFd); + + /** + * @brief Setup callback for receiving HUP event on the notification channel. + * + * @note This function takes the ownership of the passed file descriptor and + * will close it when the connection is closed. + */ + void SetupNotifyHandler(int aSocketFd, bool aAdditionalAdvertising = false); + + /// Send indication to the CHIP RX characteristic on the remote peripheral device + CHIP_ERROR SendIndication(chip::System::PacketBufferHandle apBuf); + /// Write to the CHIP RX characteristic on the remote peripheral device + CHIP_ERROR SendWriteRequest(chip::System::PacketBufferHandle apBuf); + /// Subscribe to the CHIP TX characteristic on the remote peripheral device + CHIP_ERROR SubscribeCharacteristic(); + /// Unsubscribe from the CHIP TX characteristic on the remote peripheral device + CHIP_ERROR UnsubscribeCharacteristic(); + + CHIP_ERROR CloseConnection(); + +private: struct IOChannel { - GIOChannel * mpChannel; - GSource * mWatchSource; + IOChannel() = default; + ~IOChannel(); + + GAutoPtr mChannel; + GAutoPtr mWatchSource; }; struct ConnectionDataBundle { - BluezConnection * mpConn; - GVariant * mpVal; + ConnectionDataBundle(const BluezConnection &, const chip::System::PacketBufferHandle &); + ~ConnectionDataBundle() = default; + + const BluezConnection & mConn; + GAutoPtr mData; }; - char * mpPeerAddress; - BluezDevice1 * mpDevice; - BluezGattService1 * mpService; - BluezGattCharacteristic1 * mpC1; - BluezGattCharacteristic1 * mpC2; - // additional data characteristics - BluezGattCharacteristic1 * mpC3; - - bool mIsNotify; - uint16_t mMtu; - struct IOChannel mC1Channel; - struct IOChannel mC2Channel; + CHIP_ERROR Init(); + + static CHIP_ERROR BluezDisconnect(BluezConnection * apConn); + + static gboolean WriteHandlerCallback(GIOChannel * aChannel, GIOCondition aCond, BluezConnection * apConn); + static gboolean NotifyHandlerCallback(GIOChannel * aChannel, GIOCondition aCond, BluezConnection * apConn); + + static CHIP_ERROR SendIndicationImpl(ConnectionDataBundle * data); + + static void SendWriteRequestDone(GObject * aObject, GAsyncResult * aResult, gpointer apConn); + static CHIP_ERROR SendWriteRequestImpl(ConnectionDataBundle * data); + + static void OnCharacteristicChanged(GDBusProxy * aInterface, GVariant * aChangedProperties, + const gchar * const * aInvalidatedProps, gpointer apConn); + static void SubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConn); + static CHIP_ERROR SubscribeCharacteristicImpl(BluezConnection * apConn); + + static void UnsubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConn); + static CHIP_ERROR UnsubscribeCharacteristicImpl(BluezConnection * apConn); + BluezEndpoint * mpEndpoint; -}; + BluezDevice1 * mpDevice; -CHIP_ERROR SendBluezIndication(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf); -CHIP_ERROR CloseBluezConnection(BLE_CONNECTION_OBJECT apConn); + bool mNotifyAcquired = false; + uint16_t mMtu = 0; -/// Write to the CHIP RX characteristic on the remote peripheral device -CHIP_ERROR BluezSendWriteRequest(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf); -/// Subscribe to the CHIP TX characteristic on the remote peripheral device -CHIP_ERROR BluezSubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn); -/// Unsubscribe from the CHIP TX characteristic on the remote peripheral device -CHIP_ERROR BluezUnsubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn); + BluezGattService1 * mpService = nullptr; + + BluezGattCharacteristic1 * mpC1 = nullptr; + IOChannel mC1Channel = { 0 }; + BluezGattCharacteristic1 * mpC2 = nullptr; + IOChannel mC2Channel = { 0 }; +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + BluezGattCharacteristic1 * mpC3 = nullptr; + IOChannel mC3Channel = { 0 }; +#endif +}; } // namespace Internal } // namespace DeviceLayer diff --git a/src/platform/Linux/bluez/BluezEndpoint.cpp b/src/platform/Linux/bluez/BluezEndpoint.cpp index 236533c7371221..b4f519ced3ce9d 100644 --- a/src/platform/Linux/bluez/BluezEndpoint.cpp +++ b/src/platform/Linux/bluez/BluezEndpoint.cpp @@ -310,39 +310,6 @@ static gboolean BluezCharacteristicWriteValueError(BluezGattCharacteristic1 * aC return TRUE; } -static gboolean BluezCharacteristicWriteFD(GIOChannel * aChannel, GIOCondition aCond, gpointer apEndpoint) -{ - GVariant * newVal; - uint8_t * buf = nullptr; - ssize_t len; - bool isSuccess = false; - - BluezConnection * conn = static_cast(apEndpoint); - - VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "No CHIP Bluez connection in %s", __func__)); - - VerifyOrExit(!(aCond & G_IO_HUP), ChipLogError(DeviceLayer, "INFO: socket disconnected in %s", __func__)); - VerifyOrExit(!(aCond & (G_IO_ERR | G_IO_NVAL)), ChipLogError(DeviceLayer, "INFO: socket error in %s", __func__)); - VerifyOrExit(aCond == G_IO_IN, ChipLogError(DeviceLayer, "FAIL: error in %s", __func__)); - - ChipLogDetail(DeviceLayer, "c1 %s mtu, %d", __func__, conn->mMtu); - - buf = g_new(uint8_t, conn->mMtu); - len = read(g_io_channel_unix_get_fd(aChannel), buf, conn->mMtu); - VerifyOrExit(len > 0, ChipLogError(DeviceLayer, "FAIL: short read in %s (%zd)", __func__, len)); - - // Casting len to size_t is safe, since we ensured that it's not negative. - newVal = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, buf, static_cast(len), sizeof(uint8_t)); - - bluez_gatt_characteristic1_set_value(conn->mpC1, newVal); - BLEManagerImpl::HandleRXCharWrite(conn, buf, static_cast(len)); - isSuccess = true; - -exit: - g_free(buf); - return isSuccess ? G_SOURCE_CONTINUE : G_SOURCE_REMOVE; -} - static void Bluez_gatt_characteristic1_complete_acquire_write_with_fd(GDBusMethodInvocation * invocation, int fd, guint16 mtu) { GUnixFDList * fd_list = g_unix_fd_list_new(); @@ -352,22 +319,16 @@ static void Bluez_gatt_characteristic1_complete_acquire_write_with_fd(GDBusMetho g_object_unref(fd_list); } -static gboolean bluezCharacteristicDestroyFD(GIOChannel * aChannel, GIOCondition aCond, gpointer apEndpoint) -{ - return G_SOURCE_REMOVE; -} - static gboolean BluezCharacteristicAcquireWrite(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation, GVariant * aOptions, gpointer apEndpoint) { int fds[2] = { -1, -1 }; - GIOChannel * channel; - GSource * watchSource; #if CHIP_ERROR_LOGGING char * errStr; #endif // CHIP_ERROR_LOGGING BluezConnection * conn = nullptr; GAutoPtr option_mtu; + uint16_t mtu; BluezEndpoint * endpoint = static_cast(apEndpoint); @@ -381,9 +342,9 @@ static gboolean BluezCharacteristicAcquireWrite(BluezGattCharacteristic1 * aChar ChipLogDetail(DeviceLayer, "BluezCharacteristicAcquireWrite is called, conn: %p", conn); VerifyOrReturnValue( - g_variant_lookup(aOptions, "mtu", "q", &conn->mMtu), FALSE, - ChipLogError(DeviceLayer, "FAIL: No MTU in options in %s", __func__); + g_variant_lookup(aOptions, "mtu", "q", &mtu), FALSE, ChipLogError(DeviceLayer, "FAIL: No MTU in options in %s", __func__); g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.InvalidArguments", "MTU negotiation failed")); + conn->SetMTU(mtu); if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) < 0) { @@ -395,20 +356,10 @@ static gboolean BluezCharacteristicAcquireWrite(BluezGattCharacteristic1 * aChar return FALSE; } - channel = g_io_channel_unix_new(fds[0]); - g_io_channel_set_encoding(channel, nullptr, nullptr); - g_io_channel_set_close_on_unref(channel, TRUE); - g_io_channel_set_buffered(channel, FALSE); - conn->mC1Channel.mpChannel = channel; - - watchSource = g_io_create_watch(channel, static_cast(G_IO_HUP | G_IO_IN | G_IO_ERR | G_IO_NVAL)); - g_source_set_callback(watchSource, G_SOURCE_FUNC(BluezCharacteristicWriteFD), conn, nullptr); - PlatformMgrImpl().GLibMatterContextAttachSource(watchSource); - conn->mC1Channel.mWatchSource = watchSource; - + conn->SetupWriteHandler(fds[0]); bluez_gatt_characteristic1_set_write_acquired(aChar, TRUE); - Bluez_gatt_characteristic1_complete_acquire_write_with_fd(aInvocation, fds[1], conn->mMtu); + Bluez_gatt_characteristic1_complete_acquire_write_with_fd(aInvocation, fds[1], conn->GetMTU()); close(fds[1]); return TRUE; @@ -427,17 +378,21 @@ static gboolean BluezCharacteristicAcquireNotify(BluezGattCharacteristic1 * aCha GVariant * aOptions, gpointer apEndpoint) { int fds[2] = { -1, -1 }; - GIOChannel * channel; - GSource * watchSource; #if CHIP_ERROR_LOGGING char * errStr; #endif // CHIP_ERROR_LOGGING - BluezConnection * conn = nullptr; + BluezConnection * conn = nullptr; + bool isAdditionalAdvertising = false; GAutoPtr option_mtu; + uint16_t mtu; BluezEndpoint * endpoint = static_cast(apEndpoint); VerifyOrReturnValue(endpoint != nullptr, FALSE, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__)); +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + isAdditionalAdvertising = (aChar == endpoint->mpC3); +#endif + if (bluez_gatt_characteristic1_get_notifying(aChar)) { g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotPermitted", "Already notifying"); @@ -449,10 +404,10 @@ static gboolean BluezCharacteristicAcquireNotify(BluezGattCharacteristic1 * aCha conn != nullptr, FALSE, g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection")); - VerifyOrReturnValue(g_variant_lookup(aOptions, "mtu", "q", &conn->mMtu), FALSE, { - ChipLogError(DeviceLayer, "FAIL: No MTU in options in %s", __func__); - g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.InvalidArguments", "MTU negotiation failed"); - }); + VerifyOrReturnValue( + g_variant_lookup(aOptions, "mtu", "q", &mtu), FALSE, ChipLogError(DeviceLayer, "FAIL: No MTU in options in %s", __func__); + g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.InvalidArguments", "MTU negotiation failed");); + conn->SetMTU(mtu); if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) < 0) { @@ -464,24 +419,14 @@ static gboolean BluezCharacteristicAcquireNotify(BluezGattCharacteristic1 * aCha return FALSE; } - channel = g_io_channel_unix_new(fds[0]); - g_io_channel_set_encoding(channel, nullptr, nullptr); - g_io_channel_set_close_on_unref(channel, TRUE); - g_io_channel_set_buffered(channel, FALSE); - conn->mC2Channel.mpChannel = channel; - - watchSource = g_io_create_watch(channel, static_cast(G_IO_HUP | G_IO_ERR | G_IO_NVAL)); - g_source_set_callback(watchSource, G_SOURCE_FUNC(bluezCharacteristicDestroyFD), conn, nullptr); - PlatformMgrImpl().GLibMatterContextAttachSource(watchSource); - conn->mC1Channel.mWatchSource = watchSource; - + conn->SetupNotifyHandler(fds[0], isAdditionalAdvertising); bluez_gatt_characteristic1_set_notify_acquired(aChar, TRUE); + conn->SetNotifyAcquired(true); // same reply as for AcquireWrite - Bluez_gatt_characteristic1_complete_acquire_write_with_fd(aInvocation, fds[1], conn->mMtu); + Bluez_gatt_characteristic1_complete_acquire_write_with_fd(aInvocation, fds[1], conn->GetMTU()); close(fds[1]); - conn->mIsNotify = true; BLEManagerImpl::HandleTXCharCCCDWrite(conn); return TRUE; @@ -517,7 +462,7 @@ static gboolean BluezCharacteristicStartNotify(BluezGattCharacteristic1 * aChar, { bluez_gatt_characteristic1_complete_start_notify(aChar, aInvocation); bluez_gatt_characteristic1_set_notifying(aChar, TRUE); - conn->mIsNotify = true; + conn->SetNotifyAcquired(true); BLEManagerImpl::HandleTXCharCCCDWrite(conn); } isSuccess = true; @@ -555,7 +500,7 @@ static gboolean BluezCharacteristicStopNotify(BluezGattCharacteristic1 * aChar, bluez_gatt_characteristic1_complete_start_notify(aChar, aInvocation); bluez_gatt_characteristic1_set_notifying(aChar, FALSE); } - conn->mIsNotify = false; + conn->SetNotifyAcquired(false); isSuccess = true; @@ -593,136 +538,6 @@ static gboolean BluezIsDeviceOnAdapter(BluezDevice1 * aDevice, BluezAdapter1 * a return strcmp(bluez_device1_get_adapter(aDevice), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aAdapter))) == 0 ? TRUE : FALSE; } -static gboolean BluezIsServiceOnDevice(BluezGattService1 * aService, BluezDevice1 * aDevice) -{ - return strcmp(bluez_gatt_service1_get_device(aService), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aDevice))) == 0 ? TRUE - : FALSE; -} - -static gboolean BluezIsCharOnService(BluezGattCharacteristic1 * aChar, BluezGattService1 * aService) -{ - ChipLogDetail(DeviceLayer, "Char1 %s", bluez_gatt_characteristic1_get_service(aChar)); - ChipLogDetail(DeviceLayer, "Char1 %s", g_dbus_proxy_get_object_path(G_DBUS_PROXY(aService))); - return strcmp(bluez_gatt_characteristic1_get_service(aChar), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aService))) == 0 ? TRUE - : FALSE; -} - -static void BluezConnectionInit(BluezConnection * apConn) -{ - // populate the service and the characteristics - GList * objects = nullptr; - GList * l; - BluezEndpoint * endpoint = nullptr; - - VerifyOrExit(apConn != nullptr, ChipLogError(DeviceLayer, "Bluez connection is NULL in %s", __func__)); - - endpoint = apConn->mpEndpoint; - VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__)); - - if (!endpoint->mIsCentral) - { - apConn->mpService = BLUEZ_GATT_SERVICE1(g_object_ref(apConn->mpEndpoint->mpService)); - apConn->mpC1 = BLUEZ_GATT_CHARACTERISTIC1(g_object_ref(endpoint->mpC1)); - apConn->mpC2 = BLUEZ_GATT_CHARACTERISTIC1(g_object_ref(endpoint->mpC2)); - } - else - { - objects = g_dbus_object_manager_get_objects(endpoint->mpObjMgr); - - for (l = objects; l != nullptr; l = l->next) - { - BluezObject * object = BLUEZ_OBJECT(l->data); - BluezGattService1 * service = bluez_object_get_gatt_service1(object); - - if (service != nullptr) - { - if ((BluezIsServiceOnDevice(service, apConn->mpDevice)) == TRUE && - (strcmp(bluez_gatt_service1_get_uuid(service), CHIP_BLE_UUID_SERVICE_STRING) == 0)) - { - apConn->mpService = service; - break; - } - g_object_unref(service); - } - } - - VerifyOrExit(apConn->mpService != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL service in %s", __func__)); - - for (l = objects; l != nullptr; l = l->next) - { - BluezObject * object = BLUEZ_OBJECT(l->data); - BluezGattCharacteristic1 * char1 = bluez_object_get_gatt_characteristic1(object); - - if (char1 != nullptr) - { - if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) && - (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C1_STRING) == 0)) - { - apConn->mpC1 = char1; - } - else if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) && - (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C2_STRING) == 0)) - { - apConn->mpC2 = char1; - } - else if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) && - (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C3_STRING) == 0)) - { - apConn->mpC3 = char1; - } - else - { - g_object_unref(char1); - } - if ((apConn->mpC1 != nullptr) && (apConn->mpC2 != nullptr)) - { - break; - } - } - } - - VerifyOrExit(apConn->mpC1 != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL C1 in %s", __func__)); - VerifyOrExit(apConn->mpC2 != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL C2 in %s", __func__)); - } - -exit: - if (objects != nullptr) - g_list_free_full(objects, g_object_unref); -} - -static void BluezOTConnectionDestroy(BluezConnection * aConn) -{ - if (aConn) - { - if (aConn->mpDevice) - g_object_unref(aConn->mpDevice); - if (aConn->mpService) - g_object_unref(aConn->mpService); - if (aConn->mpC1) - g_object_unref(aConn->mpC1); - if (aConn->mpC2) - g_object_unref(aConn->mpC2); - if (aConn->mpPeerAddress) - g_free(aConn->mpPeerAddress); - if (aConn->mC1Channel.mWatchSource) - { - g_source_destroy(aConn->mC1Channel.mWatchSource); - g_source_unref(aConn->mC1Channel.mWatchSource); - } - if (aConn->mC1Channel.mpChannel) - g_io_channel_unref(aConn->mC1Channel.mpChannel); - if (aConn->mC2Channel.mWatchSource) - { - g_source_destroy(aConn->mC2Channel.mWatchSource); - g_source_unref(aConn->mC2Channel.mWatchSource); - } - if (aConn->mC2Channel.mpChannel) - g_io_channel_unref(aConn->mC2Channel.mpChannel); - - g_free(aConn); - } -} - static BluezGattCharacteristic1 * BluezCharacteristicCreate(BluezGattService1 * aService, const char * aCharName, const char * aUUID, GDBusObjectManagerServer * aRoot) { @@ -801,7 +616,7 @@ static void UpdateConnectionTable(BluezDevice1 * apDevice, BluezEndpoint & aEndp BLEManagerImpl::CHIPoBluez_ConnectionClosed(connection); // TODO: the connection object should be released after BLEManagerImpl finishes cleaning up its resources // after the disconnection. Releasing it here doesn't cause any issues, but it's error-prone. - BluezOTConnectionDestroy(connection); + chip::Platform::Delete(connection); g_hash_table_remove(aEndpoint.mpConnMap, objectPath); return; } @@ -814,15 +629,11 @@ static void UpdateConnectionTable(BluezDevice1 * apDevice, BluezEndpoint & aEndp if (connection == nullptr && bluez_device1_get_connected(apDevice) && (!aEndpoint.mIsCentral || bluez_device1_get_services_resolved(apDevice))) { - connection = g_new0(BluezConnection, 1); - connection->mpPeerAddress = g_strdup(bluez_device1_get_address(apDevice)); - connection->mpDevice = static_cast(g_object_ref(apDevice)); - connection->mpEndpoint = &aEndpoint; - BluezConnectionInit(connection); + connection = chip::Platform::New(&aEndpoint, apDevice); aEndpoint.mpPeerDevicePath = g_strdup(objectPath); g_hash_table_insert(aEndpoint.mpConnMap, aEndpoint.mpPeerDevicePath, connection); - ChipLogDetail(DeviceLayer, "New BLE connection: conn %p, device %s, path %s", connection, connection->mpPeerAddress, + ChipLogDetail(DeviceLayer, "New BLE connection: conn %p, device %s, path %s", connection, connection->GetPeerAddress(), aEndpoint.mpPeerDevicePath); BLEManagerImpl::HandleNewConnection(connection); @@ -865,15 +676,11 @@ static void BluezHandleNewDevice(BluezDevice1 * device, BluezEndpoint * apEndpoi ChipLogError(DeviceLayer, "FAIL: connection already tracked: conn: %p new device: %s", conn, g_dbus_proxy_get_object_path(G_DBUS_PROXY(device)))); - conn = g_new0(BluezConnection, 1); - conn->mpPeerAddress = g_strdup(bluez_device1_get_address(device)); - conn->mpDevice = static_cast(g_object_ref(device)); - conn->mpEndpoint = apEndpoint; - BluezConnectionInit(conn); + conn = chip::Platform::New(apEndpoint, device); apEndpoint->mpPeerDevicePath = g_strdup(g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))); g_hash_table_insert(apEndpoint->mpConnMap, apEndpoint->mpPeerDevicePath, conn); - ChipLogDetail(DeviceLayer, "BLE device connected: conn %p, device %s, path %s", conn, conn->mpPeerAddress, + ChipLogDetail(DeviceLayer, "BLE device connected: conn %p, device %s, path %s", conn, conn->GetPeerAddress(), apEndpoint->mpPeerDevicePath); exit: @@ -1383,6 +1190,8 @@ static CHIP_ERROR ConnectDeviceImpl(ConnectParams * apParams) CHIP_ERROR ConnectDevice(BluezDevice1 & aDevice, BluezEndpoint * apEndpoint) { auto params = chip::Platform::New(&aDevice, apEndpoint); + VerifyOrReturnError(params != nullptr, CHIP_ERROR_NO_MEMORY); + if (PlatformMgrImpl().GLibMatterContextInvokeSync(ConnectDeviceImpl, params) != CHIP_NO_ERROR) { ChipLogError(Ble, "Failed to schedule ConnectDeviceImpl() on CHIPoBluez thread");