Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5fc8af37 authored by Hansong Zhang's avatar Hansong Zhang
Browse files

HCI Classic ACL: Queue pending connection requests

* Send next connection request after connection_complete event, if there
is already a pending outgoing connection_request,
accept_connection_request, or reject_connection_request.
* Don't allow sending connection_request, or accept connection, if there
is already a device with same Address connected.
* Also fix a memory leak in grpc_root_server and inquiry_test.

Bug: 143620554
Test: bluetooth_test_gd and cert/run_cert.sh
Change-Id: I4ea321eafa7857bfa3ad3fdfa0ebfa07a162ff4b
parent b16c44c5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -85,6 +85,7 @@ class RootCertService : public ::bluetooth::cert::RootCert::Service {

    stack_manager_.GetInstance<GrpcModule>()->StopServer();
    grpc_loop_thread_->join();
    delete grpc_loop_thread_;

    stack_manager_.ShutDown();
    delete stack_thread_;
+1 −0
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ class RootFacadeService : public ::bluetooth::facade::RootFacade::Service {

    stack_manager_.GetInstance<GrpcModule>()->StopServer();
    grpc_loop_thread_->join();
    delete grpc_loop_thread_;

    stack_manager_.ShutDown();
    delete stack_thread_;
+48 −12
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include "hci/acl_manager.h"

#include <future>
#include <queue>
#include <set>
#include <utility>

@@ -32,7 +33,9 @@ using common::Bind;
using common::BindOnce;

struct AclManager::acl_connection {
  acl_connection(AddressWithType address_with_type) : address_with_type_(address_with_type) {}
  friend AclConnection;
  AddressWithType address_with_type_;
  std::unique_ptr<AclConnection::Queue> queue_ = std::make_unique<AclConnection::Queue>(10);
  bool is_disconnected_ = false;
  ErrorCode disconnect_reason_;
@@ -244,7 +247,10 @@ struct AclManager::impl {
      return;
    }
    connecting_.insert(address);
    if (should_accept_connection_.Run(address, request.GetClassOfDevice())) {
    if (is_classic_link_already_connected(address)) {
      auto reason = RejectConnectionReason::UNACCEPTABLE_BD_ADDR;
      this->reject_connection(RejectConnectionRequestBuilder::Create(address, reason));
    } else if (should_accept_connection_.Run(address, request.GetClassOfDevice())) {
      this->accept_connection(address);
    } else {
      auto reason = RejectConnectionReason::LIMITED_RESOURCES;  // TODO: determine reason
@@ -287,7 +293,7 @@ struct AclManager::impl {
    // TODO: Check and save other connection parameters
    uint16_t handle = connection_complete.GetConnectionHandle();
    ASSERT(acl_connections_.count(handle) == 0);
    acl_connections_[handle] = {};
    acl_connections_.emplace(handle, address_with_type);
    if (acl_connections_.size() == 1 && packet_to_send_ == nullptr) {
      start_round_robin();
    }
@@ -320,7 +326,7 @@ struct AclManager::impl {
    // TODO: Check and save other connection parameters
    uint16_t handle = connection_complete.GetConnectionHandle();
    ASSERT(acl_connections_.count(handle) == 0);
    acl_connections_[handle] = {};
    acl_connections_.emplace(handle, reporting_address_with_type);
    if (acl_connections_.size() == 1 && packet_to_send_ == nullptr) {
      start_round_robin();
    }
@@ -345,13 +351,27 @@ struct AclManager::impl {
    }
    uint16_t handle = connection_complete.GetConnectionHandle();
    ASSERT(acl_connections_.count(handle) == 0);
    acl_connections_[handle] = {};
    acl_connections_.emplace(handle, AddressWithType{address, AddressType::PUBLIC_DEVICE_ADDRESS});
    if (acl_connections_.size() == 1 && packet_to_send_ == nullptr) {
      start_round_robin();
    }
    std::unique_ptr<AclConnection> connection_proxy(new AclConnection(&acl_manager_, handle, address));
    client_handler_->Post(common::BindOnce(&ConnectionCallbacks::OnConnectSuccess,
                                           common::Unretained(client_callbacks_), std::move(connection_proxy)));
    while (!pending_outgoing_connections_.empty()) {
      auto create_connection_packet_and_address = std::move(pending_outgoing_connections_.front());
      pending_outgoing_connections_.pop();
      if (!is_classic_link_already_connected(create_connection_packet_and_address.first)) {
        connecting_.insert(create_connection_packet_and_address.first);
        hci_layer_->EnqueueCommand(std::move(create_connection_packet_and_address.second),
                                   common::BindOnce([](CommandStatusView status) {
                                     ASSERT(status.IsValid());
                                     ASSERT(status.GetCommandOpCode() == OpCode::CREATE_CONNECTION);
                                   }),
                                   handler_);
        break;
      }
    }
  }

  void on_disconnection_complete(EventPacketView packet) {
@@ -837,6 +857,15 @@ struct AclManager::impl {
    }
  }

  bool is_classic_link_already_connected(Address address) {
    for (const auto& connection : acl_connections_) {
      if (connection.second.address_with_type_.GetAddress() == address) {
        return true;
      }
    }
    return false;
  }

  void create_connection(Address address) {
    // TODO: Configure default connection parameters?
    uint16_t packet_type = 0x4408 /* DM 1,3,5 */ | 0x8810 /*DH 1,3,5 */;
@@ -845,16 +874,23 @@ struct AclManager::impl {
    ClockOffsetValid clock_offset_valid = ClockOffsetValid::INVALID;
    CreateConnectionRoleSwitch allow_role_switch = CreateConnectionRoleSwitch::ALLOW_ROLE_SWITCH;
    ASSERT(client_callbacks_ != nullptr);

    connecting_.insert(address);
    std::unique_ptr<CreateConnectionBuilder> packet = CreateConnectionBuilder::Create(
        address, packet_type, page_scan_repetition_mode, clock_offset, clock_offset_valid, allow_role_switch);

    if (connecting_.empty()) {
      if (is_classic_link_already_connected(address)) {
        LOG_WARN("already connected: %s", address.ToString().c_str());
        return;
      }
      connecting_.insert(address);
      hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce([](CommandStatusView status) {
                                   ASSERT(status.IsValid());
                                   ASSERT(status.GetCommandOpCode() == OpCode::CREATE_CONNECTION);
                                 }),
                                 handler_);
    } else {
      pending_outgoing_connections_.emplace(address, std::move(packet));
    }
  }

  void create_le_connection(AddressWithType address_with_type) {
@@ -892,7 +928,6 @@ struct AclManager::impl {
      LOG_INFO("Cannot cancel non-existent connection to %s", address.ToString().c_str());
      return;
    }
    connecting_.erase(connecting_addr);
    std::unique_ptr<CreateConnectionCancelBuilder> packet = CreateConnectionCancelBuilder::Create(address);
    hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce([](CommandCompleteView complete) { /* TODO */ }),
                               handler_);
@@ -1562,6 +1597,7 @@ struct AclManager::impl {
  std::set<Address> connecting_;
  std::set<AddressWithType> connecting_le_;
  common::Callback<bool(Address, ClassOfDevice)> should_accept_connection_;
  std::queue<std::pair<Address, std::unique_ptr<CreateConnectionBuilder>>> pending_outgoing_connections_;
};

AclConnection::QueueUpEnd* AclConnection::GetAclQueueEnd() const {
+2 −0
Original line number Diff line number Diff line
@@ -267,6 +267,7 @@ class TestHciLayer : public hci::HciLayer {
    auto future = promise_sync_complete_->get_future();
    func();
    future.wait();
    delete promise_sync_complete_;
    promise_sync_complete_ = nullptr;
  }

@@ -308,6 +309,7 @@ class InquiryTest : public ::testing::Test {
    auto future = promise_result_complete_->get_future();
    func();
    future.wait();
    delete promise_result_complete_;
    promise_result_complete_ = nullptr;
  }