Add OpenL2capServerSocket and skeleton BleL2capServerSocket/BleL2capSocket

PiperOrigin-RevId: 746334743
This commit is contained in:
Edwin Wu
2025-04-11 00:01:50 -07:00
committed by Copybara-Service
parent d999507674
commit b10957d712
17 changed files with 401 additions and 36 deletions
+16 -9
View File
@@ -97,6 +97,9 @@ BleV2::~BleV2() {
while (!server_sockets_.empty()) {
StopAcceptingConnections(server_sockets_.begin()->first);
}
while (!l2cap_server_sockets_.empty()) {
StopAcceptingL2capConnections(l2cap_server_sockets_.begin()->first);
}
serial_executor_.Shutdown();
alarm_executor_.Shutdown();
@@ -175,7 +178,11 @@ ErrorOr<bool> BleV2::StartAdvertising(const std::string& service_id,
// Wrap the connections advertisement to the medium advertisement.
ByteArray service_id_hash = mediums::bleutils::GenerateHash(
service_id, mediums::BleAdvertisement::kServiceIdHashLength);
int psm = medium_.GetPSM();
int psm = mediums::BleAdvertisementHeader::kDefaultPsmValue;
const auto it = l2cap_server_sockets_.find(service_id);
if (it != l2cap_server_sockets_.end()) {
psm = it->second.GetPSM();
}
mediums::BleAdvertisement medium_advertisement = {
mediums::BleAdvertisement::Version::kV2,
mediums::BleAdvertisement::SocketVersion::kV2,
@@ -677,7 +684,7 @@ ErrorOr<bool> BleV2::StartAcceptingL2capConnections(
// Mark the fact that there's an in-progress Ble server accepting
// connections.
auto owned_server_socket =
l2cap_server_socket_map_.insert({service_id, std::move(server_socket)})
l2cap_server_sockets_.insert({service_id, std::move(server_socket)})
.first->second;
// Start the accept loop on a dedicated thread - this stays alive and
// listening for new incoming connections until StopAcceptingConnections()
@@ -701,7 +708,7 @@ ErrorOr<bool> BleV2::StartAcceptingL2capConnections(
MutexLock lock(&mutex_);
incoming_sockets_.erase(service_id);
});
l2cap_incoming_service_id_to_socket_map_.insert(
l2cap_incoming_service_id_to_sockets_.insert(
{service_id, client_socket});
}
if (callback) {
@@ -757,8 +764,8 @@ bool BleV2::StopAcceptingConnections(const std::string& service_id) {
bool BleV2::StopAcceptingL2capConnections(const std::string& service_id) {
MutexLock lock(&mutex_);
const auto it = l2cap_server_socket_map_.find(service_id);
if (it == l2cap_server_socket_map_.end()) {
const auto it = l2cap_server_sockets_.find(service_id);
if (it == l2cap_server_sockets_.end()) {
LOG(INFO) << "Can't stop accepting Ble L2CAP connections because it was "
"never started.";
return false;
@@ -768,15 +775,15 @@ bool BleV2::StopAcceptingL2capConnections(const std::string& service_id) {
// in accept_loops_thread_pool_ that blocks on BleL2capServerSocket.accept().
// That may take some time to complete, but there's no particular reason to
// wait around for it.
auto item = l2cap_server_socket_map_.extract(it);
auto item = l2cap_server_sockets_.extract(it);
// Store a handle to the BleL2capServerSocket, so we can use it after
// removing the entry from l2cap_server_socket_map_; making it scoped
// removing the entry from l2cap_server_sockets_; making it scoped
// is a bonus that takes care of deallocation before we leave this method.
BleL2capServerSocket& listening_socket = item.mapped();
// Regardless of whether or not we fail to close the existing
// BleL2capServerSocket, remove it from l2cap_server_socket_map_ so that it
// BleL2capServerSocket, remove it from l2cap_server_sockets_ so that it
// frees up this service for another round.
// Finally, close the BleL2capServerSocket.
@@ -898,7 +905,7 @@ bool BleV2::IsAcceptingConnectionsLocked(const std::string& service_id) {
}
bool BleV2::IsAcceptingL2capConnectionsLocked(const std::string& service_id) {
return l2cap_server_socket_map_.contains(service_id);
return l2cap_server_sockets_.contains(service_id);
}
bool BleV2::IsAdvertisementGattServerRunningLocked() {
+3 -3
View File
@@ -333,14 +333,14 @@ class BleV2 final {
// A map of service_id -> L2capServerSocket. If map is non-empty, we
// are currently listening for incoming connections.
absl::flat_hash_map<std::string, BleL2capServerSocket>
l2cap_server_socket_map_ ABSL_GUARDED_BY(mutex_);
absl::flat_hash_map<std::string, BleL2capServerSocket> l2cap_server_sockets_
ABSL_GUARDED_BY(mutex_);
// A map of service_id -> BleL2capSocket.
// Tracks currently connected incoming sockets. This lets the device know when
// it's okay to restart L2CAP server related operations.
absl::flat_hash_map<std::string, BleL2capSocket>
l2cap_incoming_service_id_to_socket_map_ ABSL_GUARDED_BY(mutex_);
l2cap_incoming_service_id_to_sockets_ ABSL_GUARDED_BY(mutex_);
};
} // namespace connections
@@ -369,6 +369,12 @@ Status P2pClusterPcpHandler::StopAdvertisingImpl(ClientProxy* client) {
config_package_nearby::nearby_connections_feature::kEnableBleV2)) {
ble_v2_medium_.StopAdvertising(client->GetAdvertisingServiceId());
ble_v2_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId());
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kEnableBleL2cap)) {
ble_v2_medium_.StopAcceptingL2capConnections(
client->GetAdvertisingServiceId());
}
} else {
ble_medium_.StopAdvertising(client->GetAdvertisingServiceId());
ble_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId());
@@ -1606,6 +1612,7 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl(
}
}
}
// wifi lan
if (options.enable_wlan_listening &&
!wifi_lan_medium_.IsAcceptingConnections(std::string(service_id))) {
ErrorOr<bool> wifi_lan_result = wifi_lan_medium_.StartAcceptingConnections(
+1 -2
View File
@@ -252,8 +252,7 @@ BleV2ServerSocket BleV2Medium::OpenServerSocket(const std::string& service_id) {
BleL2capServerSocket BleV2Medium::OpenL2capServerSocket(
const std::string& service_id) {
// TODO(mingshiouwu): Replace with a real implementation listening flow.
return BleL2capServerSocket(*this, nullptr);
return BleL2capServerSocket(*this, impl_->OpenL2capServerSocket(service_id));
}
BleV2Socket BleV2Medium::Connect(const std::string& service_id,
+5 -9
View File
@@ -191,8 +191,7 @@ class BleV2ServerSocket final {
std::unique_ptr<api::ble_v2::BleSocket> socket = impl_->Accept();
BleV2Peripheral peripheral;
if (!socket) {
NEARBY_LOGS(INFO) << "BleServerSocket Accept() failed on server socket: "
<< this;
LOG(INFO) << "BleServerSocket Accept() failed on server socket: " << this;
} else {
auto* platform_peripheral = socket->GetRemotePeripheral();
if (platform_peripheral != nullptr) {
@@ -204,7 +203,7 @@ class BleV2ServerSocket final {
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
Exception Close() {
NEARBY_LOGS(INFO) << "BleServerSocket Closing:: " << this;
LOG(INFO) << "BleServerSocket Closing:: " << this;
return impl_->Close();
}
@@ -381,6 +380,9 @@ class BleL2capServerSocket final {
std::unique_ptr<api::ble_v2::BleL2capServerSocket> socket)
: impl_(std::move(socket)) {}
// Gets PSM value has been published by the server.
int GetPSM() { return impl_->GetPSM(); }
// Accepts an incoming connection.
BleL2capSocket Accept() {
std::unique_ptr<api::ble_v2::BleL2capSocket> socket = impl_->Accept();
@@ -545,12 +547,6 @@ class BleV2Medium final {
impl_->AddAlternateUuidForService(uuid, service_id);
}
// Returns PSM value.
int GetPSM() {
// TODO(mingshiouwu): Replace with real implementation.
return 0;
}
private:
Mutex mutex_;
std::unique_ptr<api::ble_v2::BleMedium> impl_;
@@ -87,6 +87,10 @@ objc_library(
"ble_gatt_client.mm",
"ble_gatt_server.h",
"ble_gatt_server.mm",
"ble_l2cap_server_socket.h",
"ble_l2cap_server_socket.mm",
"ble_l2cap_socket.h",
"ble_l2cap_socket.mm",
"ble_medium.h",
"ble_medium.mm",
"ble_peripheral.h",
@@ -15,6 +15,7 @@
#import <CoreBluetooth/CoreBluetooth.h>
#import <Foundation/Foundation.h>
@class GNCBLEL2CAPStream;
@protocol GNCPeripheralManager;
NS_ASSUME_NONNULL_BEGIN
@@ -18,6 +18,7 @@
#import <Foundation/Foundation.h>
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEError.h"
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPStream.h"
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheralManager.h"
#import "GoogleToolboxForMac/GTMLogger.h"
@@ -36,7 +37,7 @@ static char *const kGNCBLEL2CAPServerQueueLabel = "com.google.nearby.GNCBLEL2CAP
GNCStartListeningL2CAPChannelCompletionHandler _startListeningL2CAPChannelcompletionHandler;
CBL2CAPChannel *_l2CAPChannel;
GNCBLEL2CAPStream *_l2CAPStream;
/// Whether start call has been performed when the peripheral was off.
BOOL _alreadyStartedWhenPeripheralPoweredOff;
}
@@ -141,6 +142,8 @@ static char *const kGNCBLEL2CAPServerQueueLabel = "com.google.nearby.GNCBLEL2CAP
if (error) {
GTMLoggerError(@"[NEARBY] Failed to unpublish L2CAP channel: %@", error);
}
[_l2CAPStream tearDown];
_l2CAPStream = nil;
_PSM = 0;
}
@@ -155,7 +158,7 @@ static char *const kGNCBLEL2CAPServerQueueLabel = "com.google.nearby.GNCBLEL2CAP
}
// Cleanup older references.
if (_l2CAPChannel) {
if (_l2CAPStream || _l2CAPChannel) {
// The device may establish a new L2CAP socket connection while the old socket is still
// connected if sysproxy stopped for a reason other than Bluetooth disconnection. Closing the
// channel here ensures the server and the client state is reset between the two
@@ -202,6 +205,8 @@ static char *const kGNCBLEL2CAPServerQueueLabel = "com.google.nearby.GNCBLEL2CAP
}
- (void)closeL2CAPChannel {
[_l2CAPStream tearDown];
_l2CAPStream = nil;
_l2CAPChannel = nil;
}
@@ -16,8 +16,6 @@
NS_ASSUME_NONNULL_BEGIN
@class GNCBLEL2CAPStream;
/// Block invoked when the stream is closed.
typedef void (^GNCBLEL2CAPStreamClosedBlock)(void);
@@ -52,6 +50,9 @@ typedef void (^GNCBLEL2CAPControllerReceivedDataBlock)(NSData *data);
/// stream is torn down.
- (void)sendData:(NSData *)data completionBlock:(void (^)(BOOL))completionBlock;
/// Closes the stream.
- (void)close;
/// Tears down the stream.
- (void)tearDown;
@@ -39,12 +39,12 @@
@interface GNCBLEL2CAPStream () <NSStreamDelegate>
/// Input stream from the watch. Operations to this stream are synchronized by |_streamQueue|
/// Input stream from the device. Operations to this stream are synchronized by |_streamQueue|
/// dispatch queue.
@property(nonatomic, nullable) NSInputStream *inputStream;
/// Output stream to the watch. Operations to this stream are synchronized by synchronized access on
/// |_writeBufferArray|.
/// Output stream to the device. Operations to this stream are synchronized by synchronized access
/// on |_writeBufferArray|.
@property(nonatomic, nullable) NSOutputStream *outputStream;
@end
@@ -56,7 +56,7 @@
/// Serial queue used when invoking |_receivedDataBlock|.
dispatch_queue_t _receivedDataQueue;
/// Queue used exclusively from events on |toWatchStream| and |fromWatchStream|.
/// Queue used exclusively from events on |inputStream| and |outputStream|.
dispatch_queue_t _streamQueue;
/// Pending data to be written to the remote device, synchronized access on itself.
@@ -99,6 +99,10 @@
return self;
}
- (void)close {
_closedBlock();
}
- (void)tearDown {
dispatch_async(_streamQueue, ^{
GTMLoggerDebug(@"[NEARBY] Closing inputStream %@ by tearDown", self.inputStream);
@@ -300,7 +304,7 @@
}
}
/// Receives data from watch and invokes |_receivedDataBlock|.
/// Receives data from device and invokes |_receivedDataBlock|.
- (void)receiveStreamData {
dispatch_assert_queue_debug(_streamQueue);
@@ -312,7 +316,7 @@
[data appendBytes:readBuffer length:(NSUInteger)bytesRead];
if (_verboseLoggingEnabled) {
GTMLoggerDebug(@"[NEARBY] Stream data from watch of length %@", @(data.length));
GTMLoggerDebug(@"[NEARBY] Stream data from device of length %@", @(data.length));
}
dispatch_async(_receivedDataQueue, ^{
@@ -0,0 +1,63 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Note: File language is detected using heuristics. Many Objective-C++ headers
// are incorrectly classified as C++ resulting in invalid linter errors. The use
// of "NSArray" and other Foundation classes like "NSData", "NSDictionary" and
// "NSUUID" are highly weighted for Objective-C and Objective-C++ scores. Oddly,
// "#import <Foundation/Foundation.h>" does not contribute any points. This
// comment alone should be enough to trick the IDE in to believing this is
// actually some sort of Objective-C file. See:
// cs/google3/devtools/search/lang/recognize_language_classifiers_data
#include <memory>
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPServer.h"
#import "internal/platform/implementation/apple/ble_l2cap_socket.h"
namespace nearby {
namespace apple {
// A BLE L2CAP server socket for listening incoming L2CAP socket.
class BleL2capServerSocket : public api::ble_v2::BleL2capServerSocket {
public:
// Creates a BLE L2CAP server socket.
//
// @param l2cap_server The L2CAP server to use.
explicit BleL2capServerSocket(GNCBLEL2CAPServer* l2cap_server);
~BleL2capServerSocket() override = default;
// Gets PSM value has been published by the server.
int GetPSM() const override;
// Blocks until either:
// - at least one incoming connection request is available, or
// - ServerSocket is closed.
// On success, returns connected socket, ready to exchange data.
// Returns nullptr on error.
// Once error is reported, it is permanent, and L2CAP ServerSocket has to be
// closed.
std::unique_ptr<api::ble_v2::BleL2capSocket> Accept() override;
// Closes the L2CAP server socket.
Exception Close() override;
private:
// The L2CAP server to use for listening incoming L2CAP socket and publishing
// PSM value.
GNCBLEL2CAPServer* l2cap_server_;
};
} // namespace apple
} // namespace nearby
@@ -0,0 +1,46 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "internal/platform/implementation/apple/ble_l2cap_server_socket.h"
#import <Foundation/Foundation.h>
#include <memory>
#include <utility>
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPServer.h"
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPStream.h"
#import "internal/platform/implementation/apple/ble_l2cap_socket.h"
#import "GoogleToolboxForMac/GTMLogger.h"
namespace nearby {
namespace apple {
BleL2capServerSocket::BleL2capServerSocket(GNCBLEL2CAPServer* l2cap_server)
: l2cap_server_(l2cap_server) {}
int BleL2capServerSocket::GetPSM() const { return [l2cap_server_ PSM]; }
std::unique_ptr<api::ble_v2::BleL2capSocket> BleL2capServerSocket::Accept() {
// TODO: edwinwu - Implement to wrap up l2cap channel with |GNCBLEL2CAPStream|.
return nullptr;
}
Exception BleL2capServerSocket::Close() {
[l2cap_server_ close];
return {Exception::kSuccess};
}
} // namespace apple
} // namespace nearby
@@ -0,0 +1,122 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <memory>
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPStream.h"
#import "internal/platform/implementation/apple/ble_peripheral.h"
#include "internal/platform/implementation/ble_v2.h"
namespace nearby {
namespace apple {
/** A readable stream of bytes. */
class BleL2capInputStream : public InputStream {
public:
// Creates a BleL2capInputStream.
//
// @param stream The underlying stream to use for reading and writing.
explicit BleL2capInputStream(GNCBLEL2CAPStream* stream);
~BleL2capInputStream() override = default;
// Reads at most `size` bytes from the input stream.
//
// Returns an empty byte array on end of file, or Exception::kIo on error.
ExceptionOr<ByteArray> Read(std::int64_t size) override;
// Closes the stream preventing further reads.
//
// Returns Exception::kIo on error, otherwise Exception::kSuccess.
Exception Close() override;
private:
GNCBLEL2CAPStream* stream_;
};
/** A writable stream of bytes. */
class BleL2capOutputStream : public OutputStream {
public:
// Creates a BleL2capOutputStream.
//
// @param stream The underlying stream to use for reading and writing.
explicit BleL2capOutputStream(GNCBLEL2CAPStream* stream);
~BleL2capOutputStream() override = default;
// Write the provided bytes to the output stream.
//
// Returns Exception::kIo on error, otherwise Exception::kSuccess.
Exception Write(const ByteArray& data) override;
// no-op
//
// Always returns Exception::kSuccess.
Exception Flush() override;
// Closes the stream preventing further writes.
//
// Returns Exception::kIo on error, otherwise Exception::kSuccess.
Exception Close() override;
private:
GNCBLEL2CAPStream* stream_;
};
/**
* Concrete BleL2capSocket implementation.
*/
class BleL2capSocket : public api::ble_v2::BleL2capSocket {
public:
explicit BleL2capSocket(GNCBLEL2CAPStream* stream);
// The peripheral used to create the socket must outlive the socket or
// undefined behavior will occur.
BleL2capSocket(GNCBLEL2CAPStream* stream,
api::ble_v2::BlePeripheral* peripheral);
~BleL2capSocket() override = default;
// Returns the InputStream of the BleL2capSocket.
// On error, returned stream will report Exception::kIo on any operation.
//
// The returned object is not owned by the caller, and can be invalidated once
// the BleL2capSocket object is destroyed.
InputStream& GetInputStream() override;
// Returns the OutputStream of the BleL2capSocket.
// On error, returned stream will report Exception::kIo on any operation.
//
// The returned object is not owned by the caller, and can be invalidated once
// the BleL2capSocket object is destroyed.
OutputStream& GetOutputStream() override;
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
Exception Close() override;
// Sets the close notifier by client side.
void SetCloseNotifier(absl::AnyInvocable<void()> notifier) override;
// Returns valid BlePeripheral pointer if there is a connection, and
// nullptr otherwise.
api::ble_v2::BlePeripheral* GetRemotePeripheral() override {
return peripheral_;
}
private:
GNCBLEL2CAPStream* stream_;
std::unique_ptr<BleL2capInputStream> input_stream_;
std::unique_ptr<BleL2capOutputStream> output_stream_;
api::ble_v2::BlePeripheral* peripheral_;
};
} // namespace apple
} // namespace nearby
@@ -0,0 +1,78 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "internal/platform/implementation/apple/ble_l2cap_socket.h"
#import <Foundation/Foundation.h>
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPStream.h"
#import "GoogleToolboxForMac/GTMLogger.h"
namespace nearby {
namespace apple {
#pragma mark - BleL2capInputStream
BleL2capInputStream::BleL2capInputStream(GNCBLEL2CAPStream* stream) : stream_(stream) {
GTMLoggerInfo(@"BleL2capInputStream::BleL2capInputStream");
}
ExceptionOr<ByteArray> BleL2capInputStream::Read(std::int64_t size) {
// TODO: edwinwu - Implement to read data from l2cap channel.
return {Exception::kIo};
}
Exception BleL2capInputStream::Close() {
// The input stream reads directly from the connection. It can not be closed without closing the
// connection itself. A call to `BleL2capSocket::Close` will close the connection.
return {Exception::kSuccess};
}
#pragma mark - BleL2capOutputStream
BleL2capOutputStream::BleL2capOutputStream(GNCBLEL2CAPStream* stream) : stream_(stream) {}
Exception BleL2capOutputStream::Write(const ByteArray& data) {
// TODO: edwinwu - Implement to write data to l2cap channel.
return {Exception::kIo};
}
Exception BleL2capOutputStream::Flush() { return {Exception::kSuccess}; }
Exception BleL2capOutputStream::Close() { return {Exception::kSuccess}; }
#pragma mark - BleL2capSocket
BleL2capSocket::BleL2capSocket(GNCBLEL2CAPStream* stream)
: BleL2capSocket(stream, new EmptyBlePeripheral()) {}
BleL2capSocket::BleL2capSocket(GNCBLEL2CAPStream* stream, api::ble_v2::BlePeripheral* peripheral)
: stream_(stream),
input_stream_(std::make_unique<BleL2capInputStream>(stream)),
output_stream_(std::make_unique<BleL2capOutputStream>(stream)),
peripheral_(peripheral) {}
InputStream& BleL2capSocket::GetInputStream() { return *input_stream_; }
OutputStream& BleL2capSocket::GetOutputStream() { return *output_stream_; }
Exception BleL2capSocket::Close() {
[stream_ close];
return {Exception::kSuccess};
}
void BleL2capSocket::SetCloseNotifier(absl::AnyInvocable<void()> notifier) {}
} // namespace apple
} // namespace nearby
@@ -118,6 +118,12 @@ class BleMedium : public api::ble_v2::BleMedium {
std::unique_ptr<api::ble_v2::BleServerSocket> OpenServerSocket(
const std::string &service_id) override;
// Opens a L2CAP server socket based on service ID.
//
// On success, returns a new BleL2capServerSocket. On error, returns nullptr.
std::unique_ptr<api::ble_v2::BleL2capServerSocket> OpenL2capServerSocket(
const std::string &service_id) override;
// TODO(b/290385712): cancellation_flag support is not yet implemented.
//
// Connects to a BLE peripheral.
@@ -35,6 +35,7 @@
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.h"
#import "internal/platform/implementation/apple/ble_gatt_client.h"
#import "internal/platform/implementation/apple/ble_gatt_server.h"
#import "internal/platform/implementation/apple/ble_l2cap_server_socket.h"
#import "internal/platform/implementation/apple/ble_peripheral.h"
#import "internal/platform/implementation/apple/ble_server_socket.h"
#import "internal/platform/implementation/apple/ble_socket.h"
@@ -42,6 +43,7 @@
#import "GoogleToolboxForMac/GTMLogger.h"
// TODO(b/293336684): Old Weave imports that need to be deleted once shared Weave is complete.
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPServer.h"
#import "internal/platform/implementation/apple/Mediums/Ble/GNCMBleConnection.h"
#import "internal/platform/implementation/apple/Mediums/Ble/GNCMBleUtils.h"
#import "internal/platform/implementation/apple/Mediums/Ble/Sockets/Source/Central/GNSCentralManager.h"
@@ -362,6 +364,29 @@ std::unique_ptr<api::ble_v2::BleServerSocket> BleMedium::OpenServerSocket(
return std::move(server_socket);
}
std::unique_ptr<api::ble_v2::BleL2capServerSocket> BleMedium::OpenL2capServerSocket(
const std::string &service_id) {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block GNCBLEL2CAPServer *block_l2cap_server = nil;
[medium_
openL2CAPServerWithCompletionHandler:^(GNCBLEL2CAPServer *server, NSError *error) {
if (error != nil) {
GTMLoggerError(@"Error opening L2CAP server: %@", error);
}
block_l2cap_server = server;
dispatch_semaphore_signal(semaphore);
}
peripheralManager:nil];
if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC)) != 0) {
GTMLoggerError(@"Opening L2CAP server timed out.");
return nullptr;
}
if (!block_l2cap_server) {
return nullptr;
}
return std::make_unique<BleL2capServerSocket>(block_l2cap_server);
}
// TODO(b/290385712): Add support for @c cancellation_flag.
// TODO(b/293336684): Old Weave code that need to be deleted once shared Weave is complete.
std::unique_ptr<api::ble_v2::BleSocket> BleMedium::Connect(const std::string &service_id,
+4 -3
View File
@@ -17,10 +17,7 @@
#include <algorithm>
#include <cstdint>
#include <limits>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
@@ -411,6 +408,9 @@ class BleL2capServerSocket {
public:
virtual ~BleL2capServerSocket() = default;
// Gets PSM value has been published by the server.
virtual int GetPSM() const = 0;
// Blocks until either:
// - at least one incoming connection request is available, or
// - ServerSocket is closed.
@@ -567,6 +567,7 @@ class BleMedium {
//
// On success, returns a new BleL2capServerSocket.
// On error, returns nullptr.
// Platform implementation should override this method if it supports L2CAP.
virtual std::unique_ptr<BleL2capServerSocket> OpenL2capServerSocket(
const std::string& service_id) {
return nullptr;