mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 15:36:12 -04:00
[BLEREFACTOR]: Add refactor flow for Ble/L2CAP in Apple platform layer.
PiperOrigin-RevId: 829179079
This commit is contained in:
committed by
Copybara-Service
parent
5caa639fcf
commit
d7a3d13fe2
@@ -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
|
||||
|
||||
@@ -36,4 +36,10 @@
|
||||
kEnableBleL2cap);
|
||||
}
|
||||
|
||||
+ (BOOL)refactorBleL2capEnabled {
|
||||
return nearby::NearbyFlags::GetInstance().GetBoolFlag(
|
||||
nearby::connections::config_package_nearby::nearby_connections_feature::
|
||||
kRefactorBleL2cap);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<api::ble::BleSocket> 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<api::ble::BleL2capSocket> 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<BleL2capSocket>(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<BleL2capSocket>(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<BleL2capSocket>(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) {
|
||||
|
||||
Reference in New Issue
Block a user