diff --git a/connections/implementation/flags/nearby_connections_feature_flags.h b/connections/implementation/flags/nearby_connections_feature_flags.h index e31b9602..ade07be9 100644 --- a/connections/implementation/flags/nearby_connections_feature_flags.h +++ b/connections/implementation/flags/nearby_connections_feature_flags.h @@ -52,6 +52,9 @@ constexpr auto kEnableBleL2cap = // Disable/Enable BLE v2 in Nearby Connections SDK. constexpr auto kEnableBleV2 = flags::Flag(kConfigPackage, "45401515", true); +// When true, refactor the BLE/L2CAP logic in Nearby Connections SDK. +constexpr auto kRefactorBleL2cap = + flags::Flag(kConfigPackage, "45713654", false); // Enable/Disable DCT advertising/scanning specification. constexpr auto kEnableDct = flags::Flag(kConfigPackage, "45697202", false); diff --git a/connections/implementation/p2p_cluster_pcp_handler.cc b/connections/implementation/p2p_cluster_pcp_handler.cc index c882bf51..d431a190 100644 --- a/connections/implementation/p2p_cluster_pcp_handler.cc +++ b/connections/implementation/p2p_cluster_pcp_handler.cc @@ -226,8 +226,7 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartAdvertisingImpl( if (ble_medium_.StartLegacyAdvertising( service_id, local_endpoint_id, advertising_options.fast_advertisement_service_uuid)) { - LOG(INFO) << __func__ - << "Ble started advertising for legacy device."; + LOG(INFO) << __func__ << "Ble started advertising for legacy device."; mediums_started_successfully.push_back(bluetooth_medium); VLOG(1) << __func__ << "After Ble, BT added"; bluetooth_classic_advertiser_client_id_ = client->GetClientId(); @@ -2379,49 +2378,68 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BleConnectImpl( config_package_nearby::nearby_connections_feature::kEnableBleL2cap) && peripheral.GetPsm() != mediums::BleAdvertisementHeader::kDefaultPsmValue) { - ErrorOr ble_l2cap_socket_result = - ble_medium_.ConnectOverL2cap( - endpoint->service_id, peripheral, - client->GetCancellationFlag(endpoint->endpoint_id)); - if (!ble_l2cap_socket_result.has_error()) { - LOG(INFO) << "In BleConnectImpl(), connected to Ble L2CAP device " - << absl::BytesToHexString(peripheral.GetId().data()) - << " for endpoint(id=" << endpoint->endpoint_id << ")."; - auto channel = std::make_unique( - endpoint->service_id, /*channel_name=*/endpoint->endpoint_id, - ble_l2cap_socket_result.value()); - return BasePcpHandler::ConnectImplResult{ - .medium = BLE, - .status = {Status::kSuccess}, - .operation_result_code = OperationResultCode::DETAIL_SUCCESS, - .endpoint_channel = std::move(channel), - }; + if (NearbyFlags::GetInstance().GetBoolFlag( + config_package_nearby::nearby_connections_feature:: + kRefactorBleL2cap)) { + // TODO(edwinwu): Implement refactored Ble L2CAP flow in next cl. + LOG(WARNING) + << "In BleConnectImpl(), failed to connect to Ble L2CAP " + "device due to refactor Ble L2CAP flow is not implemented yet."; } else { - LOG(WARNING) << "In BleConnectImpl(), failed to connect to Ble L2CAP " - "device " - << absl::BytesToHexString(peripheral.GetId().data()) - << " for endpoint(id=" << endpoint->endpoint_id << ")."; + ErrorOr ble_l2cap_socket_result = + ble_medium_.ConnectOverL2cap( + endpoint->service_id, peripheral, + client->GetCancellationFlag(endpoint->endpoint_id)); + if (!ble_l2cap_socket_result.has_error()) { + LOG(INFO) << "In BleConnectImpl(), connected to Ble L2CAP device " + << absl::BytesToHexString(peripheral.GetId().data()) + << " for endpoint(id=" << endpoint->endpoint_id << ")."; + auto channel = std::make_unique( + endpoint->service_id, /*channel_name=*/endpoint->endpoint_id, + ble_l2cap_socket_result.value()); + return BasePcpHandler::ConnectImplResult{ + .medium = BLE, + .status = {Status::kSuccess}, + .operation_result_code = OperationResultCode::DETAIL_SUCCESS, + .endpoint_channel = std::move(channel), + }; + } else { + LOG(WARNING) << "In BleConnectImpl(), failed to connect to Ble L2CAP " + "device " + << absl::BytesToHexString(peripheral.GetId().data()) + << " for endpoint(id=" << endpoint->endpoint_id << ")."; + } } } - ErrorOr ble_socket_result = - ble_medium_.Connect(endpoint->service_id, peripheral, - client->GetCancellationFlag(endpoint->endpoint_id)); - if (ble_socket_result.has_error()) { - LOG(ERROR) << "In BleConnectImpl(), failed to connect to BLE device " - << absl::BytesToHexString(peripheral.GetId().data()) - << " for endpoint(id=" << endpoint->endpoint_id << ")."; + std::unique_ptr channel = nullptr; + if (NearbyFlags::GetInstance().GetBoolFlag( + config_package_nearby::nearby_connections_feature:: + kRefactorBleL2cap)) { + // TODO(edwinwu): Implement refactored Ble L2CAP flow in next cl. return BasePcpHandler::ConnectImplResult{ .status = {Status::kBleError}, - .operation_result_code = - ble_socket_result.error().operation_result_code().value(), + .operation_result_code = OperationResultCode::DETAIL_UNKNOWN, }; + } else { + ErrorOr ble_socket_result = + ble_medium_.Connect(endpoint->service_id, peripheral, + client->GetCancellationFlag(endpoint->endpoint_id)); + if (ble_socket_result.has_error()) { + LOG(ERROR) << "In BleConnectImpl(), failed to connect to BLE device " + << absl::BytesToHexString(peripheral.GetId().data()) + << " for endpoint(id=" << endpoint->endpoint_id << ")."; + return BasePcpHandler::ConnectImplResult{ + .status = {Status::kBleError}, + .operation_result_code = + ble_socket_result.error().operation_result_code().value(), + }; + } + channel = std::make_unique( + endpoint->service_id, /*channel_name=*/endpoint->endpoint_id, + ble_socket_result.value()); } - auto channel = std::make_unique( - endpoint->service_id, /*channel_name=*/endpoint->endpoint_id, - ble_socket_result.value()); - return BasePcpHandler::ConnectImplResult{ .medium = BLE, .status = {Status::kSuccess}, diff --git a/internal/platform/implementation/apple/Flags/GNCFeatureFlags.h b/internal/platform/implementation/apple/Flags/GNCFeatureFlags.h index 65c203cf..7d75da5d 100644 --- a/internal/platform/implementation/apple/Flags/GNCFeatureFlags.h +++ b/internal/platform/implementation/apple/Flags/GNCFeatureFlags.h @@ -26,4 +26,7 @@ /** Checks whether BLE L2CAP is enabled in the Nearby Connections SDK. */ @property(nonatomic, class, readonly) BOOL bleL2capEnabled; +/** Checks whether BLE L2CAP refactor is enabled in the Nearby Connections SDK. */ +@property(nonatomic, class, readonly) BOOL refactorBleL2capEnabled; + @end diff --git a/internal/platform/implementation/apple/Flags/GNCFeatureFlags.mm b/internal/platform/implementation/apple/Flags/GNCFeatureFlags.mm index 5c47849d..548518e8 100644 --- a/internal/platform/implementation/apple/Flags/GNCFeatureFlags.mm +++ b/internal/platform/implementation/apple/Flags/GNCFeatureFlags.mm @@ -36,4 +36,10 @@ kEnableBleL2cap); } ++ (BOOL)refactorBleL2capEnabled { + return nearby::NearbyFlags::GetInstance().GetBoolFlag( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kRefactorBleL2cap); +} + @end diff --git a/internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPConnection.m b/internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPConnection.m index 41951f41..cbf9f013 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPConnection.m +++ b/internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPConnection.m @@ -16,6 +16,7 @@ #import +#import "internal/platform/implementation/apple/Flags/GNCFeatureFlags.h" #import "internal/platform/implementation/apple/Log/GNCLogger.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPStream.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCLeaks.h" @@ -98,8 +99,12 @@ static NSData *PrefixLengthData(NSData *data) { dispatch_async(_selfQueue, ^{ NSData *packet; - // Prefix the service ID hash. - packet = PrefixLengthData(PrefixDataWithServiceIDHash(_serviceIDHash, data)); + if (GNCFeatureFlags.refactorBleL2capEnabled) { + packet = PrefixLengthData(data); + } else { + // Prefix the service ID hash. + packet = PrefixLengthData(PrefixDataWithServiceIDHash(_serviceIDHash, data)); + } if (_verboseLoggingEnabled) { GNCLoggerDebug(@"GNCBLEL2CAPConnection data to be sent: %@", [packet description]); } @@ -202,42 +207,49 @@ static NSData *PrefixLengthData(NSData *data) { } bytesProcessed = realData.length + kL2CAPPacketLength; - // TODO: b/399815436 - Refactor the validation logic to connections layer. - if ([self handleL2CAPPacketFromData:realData]) { - return bytesProcessed; - } + if (GNCFeatureFlags.refactorBleL2capEnabled) { + if (_connectionHandlers.payloadHandler) { + dispatch_async(_callbackQueue, ^{ + _connectionHandlers.payloadHandler([realData copy]); + }); + } + } else { + // TODO: b/399815436 - Refactor the validation logic to connections layer. + if ([self handleL2CAPPacketFromData:realData]) { + return bytesProcessed; + } - // TODO: b/399815436 - All BLE control packets should be handled here and not passed to - // upper layer. Need to refine the flow after refactoring. - if (_incomingConnection && !_handledReceivedBLEIntroPacket) { - [self handleBLEIntroPacketFromData:realData]; - return bytesProcessed; - } + // TODO: b/399815436 - All BLE control packets should be handled here and not passed to + // upper layer. Need to refine the flow after refactoring. + if (_incomingConnection && !_handledReceivedBLEIntroPacket) { + [self handleBLEIntroPacketFromData:realData]; + return bytesProcessed; + } - if (realData.length < _serviceIDHash.length) { - GNCLoggerError(@"Data length mismatch. Expected size: > %lu, Data: %@", _serviceIDHash.length, - realData); - return bytesProcessed; - } + if (realData.length < _serviceIDHash.length) { + GNCLoggerError(@"Data length mismatch. Expected size: > %lu, Data: %@", _serviceIDHash.length, + realData); + return bytesProcessed; + } - // Extract the service ID prefix from each data packet and validate it. - NSUInteger prefixLength = _serviceIDHash.length; - if (![[realData subdataWithRange:NSMakeRange(0, prefixLength)] isEqual:_serviceIDHash]) { - return bytesProcessed; - } + // Extract the service ID prefix from each data packet and validate it. + NSUInteger prefixLength = _serviceIDHash.length; + if (![[realData subdataWithRange:NSMakeRange(0, prefixLength)] isEqual:_serviceIDHash]) { + return bytesProcessed; + } - dispatch_async(_selfQueue, ^{ - [_stream sendData:PrefixLengthData(GNCMGenerateBLEFramesPacketAcknowledgementPacket( - _serviceIDHash, realData.length)) - completionBlock:^(BOOL result){ - }]; - }); - if (_connectionHandlers.payloadHandler) { - dispatch_async(_callbackQueue, ^{ - _connectionHandlers.payloadHandler([NSData - dataWithData:[realData subdataWithRange:NSMakeRange(prefixLength, - realData.length - prefixLength)]]); + dispatch_async(_selfQueue, ^{ + [_stream sendData:PrefixLengthData(GNCMGenerateBLEFramesPacketAcknowledgementPacket( + _serviceIDHash, realData.length)) + completionBlock:^(BOOL result){ + }]; }); + if (_connectionHandlers.payloadHandler) { + dispatch_async(_callbackQueue, ^{ + _connectionHandlers.payloadHandler( + [realData subdataWithRange:NSMakeRange(prefixLength, realData.length - prefixLength)]); + }); + } } return bytesProcessed; } diff --git a/internal/platform/implementation/apple/Mediums/BLE/GNCMBleConnection.m b/internal/platform/implementation/apple/Mediums/BLE/GNCMBleConnection.m index 0a8237cd..7d41ebe0 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/GNCMBleConnection.m +++ b/internal/platform/implementation/apple/Mediums/BLE/GNCMBleConnection.m @@ -14,6 +14,7 @@ #import "internal/platform/implementation/apple/Mediums/BLE/GNCMBleConnection.h" +#import "internal/platform/implementation/apple/Flags/GNCFeatureFlags.h" #import "internal/platform/implementation/apple/Log/GNCLogger.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCLeaks.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCMBleUtils.h" @@ -58,14 +59,18 @@ NS_ASSUME_NONNULL_BEGIN completion:(GNCMPayloadResultHandler)completion { dispatch_async(_selfQueue, ^{ NSMutableData *packet; - if (data.length == 0) { - // Get the Control introduction packet if data length is 0. - NSData *introData = GNCMGenerateBLEFramesIntroductionPacket(_serviceIDHash); - packet = [NSMutableData dataWithData:introData]; + if (GNCFeatureFlags.refactorBleL2capEnabled) { + packet = [NSMutableData dataWithData:data]; } else { - // Prefix the service ID hash. - packet = [NSMutableData dataWithData:_serviceIDHash]; - [packet appendData:data]; + if (data.length == 0) { + // Get the Control introduction packet if data length is 0. + NSData *introData = GNCMGenerateBLEFramesIntroductionPacket(_serviceIDHash); + packet = [NSMutableData dataWithData:introData]; + } else { + // Prefix the service ID hash. + packet = [NSMutableData dataWithData:_serviceIDHash]; + [packet appendData:data]; + } } [_socket sendData:packet @@ -100,46 +105,55 @@ NS_ASSUME_NONNULL_BEGIN } - (void)socket:(GNSSocket *)socket didReceiveData:(NSData *)data { - // Extract the service ID prefix from each data packet. - NSMutableData *packet; - NSUInteger prefixLength = _serviceIDHash.length; - if (_expectedIntroPacket && !_receivedIntroPacket) { - // Check if the first packet is intro packet. - if (!_serviceIDHash) { - // If _serviceIdHash is nil, then we need to parse the first incoming packet if it conforms to - // introducion packet and extract the serviceIdHash for coming packets. - NSData *serviceIDHash = GNCMParseBLEFramesIntroductionPacket(data); - if (serviceIDHash) { - _serviceIDHash = serviceIDHash; - _receivedIntroPacket = YES; - } else { - GNCLoggerInfo(@"[NEARBY] Input stream: Received wrong intro packet and discarded"); + if (GNCFeatureFlags.refactorBleL2capEnabled) { + dispatch_async(_selfQueue, ^{ + if (_connectionHandlers.payloadHandler) { + dispatch_async(_callbackQueue, ^{ + _connectionHandlers.payloadHandler([data copy]); + }); } - } else { - NSData *introData = GNCMGenerateBLEFramesIntroductionPacket(_serviceIDHash); - if ([data isEqual:introData]) { - _receivedIntroPacket = YES; + }); + } else { + // Extract the service ID prefix from each data packet. + NSData *packet; + NSUInteger prefixLength = _serviceIDHash.length; + if (_expectedIntroPacket && !_receivedIntroPacket) { + // Check if the first packet is intro packet. + if (!_serviceIDHash) { + // If _serviceIdHash is nil, then we need to parse the first incoming packet if it conforms + // to introducion packet and extract the serviceIdHash for coming packets. + NSData *serviceIDHash = GNCMParseBLEFramesIntroductionPacket(data); + if (serviceIDHash) { + _serviceIDHash = serviceIDHash; + _receivedIntroPacket = YES; + } else { + GNCLoggerInfo(@"[NEARBY] Input stream: Received wrong intro packet and discarded"); + } } else { - GNCLoggerInfo(@"[NEARBY] Input stream: Received wrong intro packet and discarded"); + NSData *introData = GNCMGenerateBLEFramesIntroductionPacket(_serviceIDHash); + if ([data isEqual:introData]) { + _receivedIntroPacket = YES; + } else { + GNCLoggerInfo(@"[NEARBY] Input stream: Received wrong intro packet and discarded"); + } } + return; } - return; - } - if (![[data subdataWithRange:NSMakeRange(0, prefixLength)] isEqual:_serviceIDHash]) { - GNCLoggerInfo(@"[NEARBY] Input stream: Received wrong data packet and discarded"); - return; - } - packet = [NSMutableData - dataWithData:[data subdataWithRange:NSMakeRange(prefixLength, data.length - prefixLength)]]; - - dispatch_async(_selfQueue, ^{ - if (_connectionHandlers.payloadHandler) { - dispatch_async(_callbackQueue, ^{ - _connectionHandlers.payloadHandler(packet); - }); + if (![[data subdataWithRange:NSMakeRange(0, prefixLength)] isEqual:_serviceIDHash]) { + GNCLoggerInfo(@"[NEARBY] Input stream: Received wrong data packet and discarded"); + return; } - }); + packet = [data subdataWithRange:NSMakeRange(prefixLength, data.length - prefixLength)]; + + dispatch_async(_selfQueue, ^{ + if (_connectionHandlers.payloadHandler) { + dispatch_async(_callbackQueue, ^{ + _connectionHandlers.payloadHandler(packet); + }); + } + }); + } } @end diff --git a/internal/platform/implementation/apple/ble_medium.mm b/internal/platform/implementation/apple/ble_medium.mm index dbb3af30..c9d7ef35 100644 --- a/internal/platform/implementation/apple/ble_medium.mm +++ b/internal/platform/implementation/apple/ble_medium.mm @@ -27,6 +27,7 @@ #include "internal/platform/implementation/ble.h" #include "internal/platform/implementation/bluetooth_adapter.h" +#import "internal/platform/implementation/apple/Flags/GNCFeatureFlags.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTCharacteristic.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTClient.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTServer.h" @@ -628,8 +629,10 @@ std::unique_ptr BleMedium::Connect( return nullptr; } - // Send the (empty) intro packet, which the BLE advertiser is expecting. - socket->GetOutputStream().Write(ByteArray()); + if (!GNCFeatureFlags.refactorBleL2capEnabled) { + // Send the (empty) intro packet, which the BLE advertiser is expecting. + socket->GetOutputStream().Write(ByteArray()); + } return std::move(socket); } @@ -658,17 +661,22 @@ std::unique_ptr BleMedium::ConnectOverL2cap( serviceID:@(service_id_str.c_str()) incomingConnection:NO callbackQueue:connection_callback_queue_]; - // Blocked call to wait for the packet validation result. - // TODO: b/419654808 - Remove this once the packet validation is moved to the - // Connections layer. - [connection requestDataConnectionWithCompletion:^(BOOL result) { - if (result) { - socket = std::make_unique(connection, peripheral_id); - } - GNCLoggerInfo(result ? @"[NEARBY] Request data connection is ok" - : @"[NEARBY] Request data connection is not ok"); + if (GNCFeatureFlags.refactorBleL2capEnabled) { + socket = std::make_unique(connection, peripheral_id); dispatch_semaphore_signal(semaphore); - }]; + } else { + // Blocked call to wait for the packet validation result. + // TODO: b/419654808 - Remove this once the packet validation is moved to the + // Connections layer. + [connection requestDataConnectionWithCompletion:^(BOOL result) { + if (result) { + socket = std::make_unique(connection, peripheral_id); + } + GNCLoggerInfo(result ? @"[NEARBY] Request data connection is ok" + : @"[NEARBY] Request data connection is not ok"); + dispatch_semaphore_signal(semaphore); + }]; + } }]; dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, kApiTimeoutInSeconds * NSEC_PER_SEC); if (dispatch_semaphore_wait(semaphore, timeout) != 0) {