910e62b5创建于 1月15日历史提交
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/bluetooth/floss/floss_socket_manager.h"

#include "base/containers/contains.h"
#include "base/types/expected.h"

namespace floss {
namespace {
void HandleExported(const std::string& method_name,
                    const std::string& interface_name,
                    const std::string& object_path,
                    bool success) {
  DVLOG(1) << (success ? "Successfully exported " : "Failed to export ")
           << method_name << " on interface = " << interface_name
           << ", object = " << object_path;
}

constexpr char kListeningPropId[] = "id";
constexpr char kListeningPropSockType[] = "sock_type";
constexpr char kListeningPropFlags[] = "flags";
constexpr char kListeningPropPsm[] = "psm";
constexpr char kListeningPropChannel[] = "channel";
constexpr char kListeningPropName[] = "name";
constexpr char kListeningPropUuid[] = "uuid";

constexpr char kConnectingPropId[] = "id";
constexpr char kConnectingPropRemoteDevice[] = "remote_device";
constexpr char kConnectingPropSockType[] = "sock_type";
constexpr char kConnectingPropFlags[] = "flags";
constexpr char kConnectingPropFd[] = "fd";
constexpr char kConnectingPropPort[] = "port";
constexpr char kConnectingPropUuid[] = "uuid";
constexpr char kConnectingPropMaxRxSize[] = "max_rx_size";
constexpr char kConnectingPropMaxTxSize[] = "max_tx_size";

constexpr char kResultPropStatus[] = "status";
constexpr char kResultPropId[] = "id";
}  // namespace

template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader,
                                    FlossSocketManager::SocketType* type) {
  uint32_t raw_type = 0;
  bool read = FlossDBusClient::ReadDBusParam(reader, &raw_type);

  if (read) {
    *type = static_cast<FlossSocketManager::SocketType>(raw_type);
  }

  return read;
}

template <>
void FlossDBusClient::WriteDBusParam(
    dbus::MessageWriter* writer,
    const FlossSocketManager::SocketType& type) {
  WriteDBusParam(writer, static_cast<uint32_t>(type));
}

template <>
bool FlossDBusClient::ReadDBusParam(
    dbus::MessageReader* reader,
    FlossSocketManager::FlossListeningSocket* socket) {
  dbus::MessageReader array(nullptr);
  dbus::MessageReader dict(nullptr);

  std::map<std::string, bool> required_keys = {
      {kListeningPropId, false},      {kListeningPropSockType, false},
      {kListeningPropFlags, false},   {kListeningPropPsm, false},
      {kListeningPropChannel, false}, {kListeningPropName, false},
      {kListeningPropUuid, false},
  };

  if (!reader->PopArray(&array)) {
    return false;
  }

  while (array.PopDictEntry(&dict)) {
    std::string key;
    dict.PopString(&key);

    if (base::Contains(required_keys, key)) {
      if (key == kListeningPropId) {
        required_keys[key] = ReadDBusParamFromVariant(&dict, &socket->id);
      } else if (key == kListeningPropSockType) {
        required_keys[key] = ReadDBusParamFromVariant(&dict, &socket->type);
      } else if (key == kListeningPropFlags) {
        required_keys[key] = ReadDBusParamFromVariant(&dict, &socket->flags);
      } else if (key == kListeningPropPsm) {
        required_keys[key] =
            ReadDBusParamFromVariant<std::optional<int>>(&dict, &socket->psm);
      } else if (key == kListeningPropChannel) {
        required_keys[key] = ReadDBusParamFromVariant<std::optional<int>>(
            &dict, &socket->channel);
      } else if (key == kListeningPropName) {
        required_keys[key] =
            ReadDBusParamFromVariant<std::optional<std::string>>(&dict,
                                                                 &socket->name);
      } else if (key == kListeningPropUuid) {
        required_keys[key] =
            ReadDBusParamFromVariant<std::optional<device::BluetoothUUID>>(
                &dict, &socket->uuid);
      }
    }
  }

  // Make sure all required keys were correctly parsed.
  bool result = true;
  for (auto [key, found] : required_keys) {
    result = result && found;
  }

  return result;
}

template bool
FlossDBusClient::ReadDBusParam<FlossSocketManager::FlossListeningSocket>(
    dbus::MessageReader* reader,
    std::optional<FlossSocketManager::FlossListeningSocket>* socket);

template <>
void FlossDBusClient::WriteDBusParam(
    dbus::MessageWriter* writer,
    const FlossSocketManager::FlossListeningSocket& socket) {
  dbus::MessageWriter array(nullptr);
  dbus::MessageWriter dict(nullptr);

  writer->OpenArray("{sv}", &array);

  WriteDictEntry(&array, kListeningPropId, socket.id);
  WriteDictEntry(&array, kListeningPropSockType, socket.type);
  WriteDictEntry(&array, kListeningPropFlags, socket.flags);
  WriteDictEntry(&array, kListeningPropPsm, socket.psm);
  WriteDictEntry(&array, kListeningPropChannel, socket.channel);
  WriteDictEntry(&array, kListeningPropName, socket.name);
  WriteDictEntry(&array, kListeningPropUuid, socket.uuid);

  writer->CloseContainer(&array);
}

template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader,
                                    FlossSocketManager::FlossSocket* socket) {
  dbus::MessageReader array(nullptr);
  dbus::MessageReader dict(nullptr);
  std::map<std::string, bool> required_keys = {
      {kConnectingPropId, false},        {kConnectingPropRemoteDevice, false},
      {kConnectingPropSockType, false},  {kConnectingPropFlags, false},
      {kConnectingPropFd, false},        {kConnectingPropPort, false},
      {kConnectingPropUuid, false},      {kConnectingPropMaxRxSize, false},
      {kConnectingPropMaxTxSize, false},
  };
  if (!reader->PopArray(&array)) {
    return false;
  }

  while (array.PopDictEntry(&dict)) {
    std::string key;
    dict.PopString(&key);

    if (base::Contains(required_keys, key)) {
      if (key == kConnectingPropId) {
        required_keys[key] = ReadDBusParamFromVariant(&dict, &socket->id);
      } else if (key == kConnectingPropRemoteDevice) {
        required_keys[key] =
            ReadDBusParamFromVariant(&dict, &socket->remote_device);
      } else if (key == kConnectingPropSockType) {
        required_keys[key] = ReadDBusParamFromVariant(&dict, &socket->type);
      } else if (key == kConnectingPropFlags) {
        required_keys[key] = ReadDBusParamFromVariant(&dict, &socket->flags);
      } else if (key == kConnectingPropFd) {
        required_keys[key] =
            ReadDBusParamFromVariant<std::optional<base::ScopedFD>>(
                &dict, &socket->fd);
      } else if (key == kConnectingPropPort) {
        required_keys[key] = ReadDBusParamFromVariant(&dict, &socket->port);
      } else if (key == kConnectingPropUuid) {
        required_keys[key] =
            ReadDBusParamFromVariant<std::optional<device::BluetoothUUID>>(
                &dict, &socket->uuid);
      } else if (key == kConnectingPropMaxRxSize) {
        required_keys[key] =
            ReadDBusParamFromVariant(&dict, &socket->max_rx_size);
      } else if (key == kConnectingPropMaxTxSize) {
        required_keys[key] =
            ReadDBusParamFromVariant(&dict, &socket->max_tx_size);
      }
    }
  }

  // Make sure all required keys were correctly parsed.
  bool result = true;
  for (auto [key, found] : required_keys) {
    result = result && found;
  }

  return result;
}

template bool FlossDBusClient::ReadDBusParam<FlossSocketManager::FlossSocket>(
    dbus::MessageReader* reader,
    std::optional<FlossSocketManager::FlossSocket>* socket);

template <>
void FlossDBusClient::WriteDBusParam(
    dbus::MessageWriter* writer,
    const FlossSocketManager::FlossSocket& socket) {
  dbus::MessageWriter array(nullptr);
  dbus::MessageWriter dict(nullptr);

  writer->OpenArray("{sv}", &array);

  WriteDictEntry(&array, kConnectingPropId, socket.id);
  WriteDictEntry(&array, kConnectingPropRemoteDevice, socket.remote_device);
  WriteDictEntry(&array, kConnectingPropSockType, socket.type);
  WriteDictEntry(&array, kConnectingPropFlags, socket.flags);
  WriteDictEntry(&array, kConnectingPropFd, socket.fd);
  WriteDictEntry(&array, kConnectingPropPort, socket.port);
  WriteDictEntry(&array, kConnectingPropUuid, socket.uuid);
  WriteDictEntry(&array, kConnectingPropMaxRxSize, socket.max_rx_size);
  WriteDictEntry(&array, kConnectingPropMaxTxSize, socket.max_tx_size);

  writer->CloseContainer(&array);
}

template <>
bool FlossDBusClient::ReadDBusParam(
    dbus::MessageReader* reader,
    FlossSocketManager::SocketResult* socket_result) {
  dbus::MessageReader array(nullptr);
  dbus::MessageReader dict(nullptr);

  std::map<std::string, bool> required_keys = {
      {kResultPropStatus, false},
      {kResultPropId, false},
  };

  if (!reader->PopArray(&array)) {
    return false;
  }

  while (array.PopDictEntry(&dict)) {
    std::string key;
    dict.PopString(&key);

    if (base::Contains(required_keys, key)) {
      if (key == kResultPropStatus) {
        required_keys[key] =
            ReadDBusParamFromVariant(&dict, &socket_result->status);
      } else if (key == kResultPropId) {
        required_keys[key] =
            ReadDBusParamFromVariant(&dict, &socket_result->id);
      }
    }
  }

  // Make sure all required keys were correctly parsed.
  bool result = true;
  for (auto [key, found] : required_keys) {
    result = result && found;
  }

  return result;
}

template <>
void FlossDBusClient::WriteDBusParam(
    dbus::MessageWriter* writer,
    const FlossSocketManager::SocketResult& socket_result) {
  dbus::MessageWriter array(nullptr);
  dbus::MessageWriter dict(nullptr);

  writer->OpenArray("{sv}", &array);

  WriteDictEntry(&array, kResultPropStatus,
                 static_cast<uint32_t>(socket_result.status));
  WriteDictEntry(&array, kResultPropId, socket_result.id);

  writer->CloseContainer(&array);
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(const FlossSocketManager::SocketType*) {
  static DBusTypeInfo info{"u", "SocketType"};
  return info;
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(const FlossSocketManager::FlossSocket*) {
  static DBusTypeInfo info{"a{sv}", "FlossSocket"};
  return info;
}

int FlossSocketManager::GetRawFlossFlagsFromBluetoothFlags(bool encrypt,
                                                           bool auth,
                                                           bool auth_mitm,
                                                           bool auth_16_digit,
                                                           bool no_sdp) {
  int flags = 0;
  return flags |
         (encrypt ? static_cast<int>(SocketFlags::kSocketFlagsEncrypt) : 0) |
         (auth ? static_cast<int>(SocketFlags::kSocketFlagsAuth) : 0) |
         (auth_mitm ? static_cast<int>(SocketFlags::kSocketFlagsAuthMitm) : 0) |
         (auth_16_digit ? static_cast<int>(SocketFlags::kSocketFlagsAuth16Digit)
                        : 0) |
         (no_sdp ? static_cast<int>(SocketFlags::kSocketFlagsNoSdp) : 0);
}

FlossSocketManager::FlossListeningSocket::FlossListeningSocket() = default;
FlossSocketManager::FlossListeningSocket::FlossListeningSocket(
    const FlossListeningSocket&) = default;
FlossSocketManager::FlossListeningSocket::~FlossListeningSocket() = default;

FlossSocketManager::FlossSocket::FlossSocket() = default;
FlossSocketManager::FlossSocket::FlossSocket(FlossSocket&&) = default;
FlossSocketManager::FlossSocket::~FlossSocket() = default;

// static
const char FlossSocketManager::kErrorInvalidCallback[] =
    "org.chromium.Error.InvalidCallbackId";

// static
const char FlossSocketManager::kExportedCallbacksPath[] =
    "/org/chromium/bluetooth/socket_manager/callback";

// static
std::unique_ptr<FlossSocketManager> FlossSocketManager::Create() {
  return std::make_unique<FlossSocketManager>();
}

FlossSocketManager::FlossSocketManager() = default;

FlossSocketManager::~FlossSocketManager() {
  if (callback_id_ != kInvalidCallbackId) {
    CallSocketMethod(
        base::BindOnce(&FlossSocketManager::CompleteUnregisterCallback,
                       weak_ptr_factory_.GetWeakPtr()),
        socket_manager::kUnregisterCallback, callback_id_);
  }
  if (bus_) {
    bus_->UnregisterExportedObject(dbus::ObjectPath(kExportedCallbacksPath));
  }
}

void FlossSocketManager::ListenUsingL2cap(
    const Security security_level,
    ResponseCallback<BtifStatus> callback,
    ConnectionStateChanged ready_cb,
    ConnectionAccepted new_connection_cb) {
  if (callback_id_ == kInvalidCallbackId) {
    std::move(callback).Run(base::unexpected(Error(kErrorInvalidCallback, "")));
    return;
  }

  const char* method = security_level == Security::kInsecure
                           ? socket_manager::kListenUsingInsecureL2capChannel
                           : socket_manager::kListenUsingL2capChannel;

  CallSocketMethod(
      base::BindOnce(&FlossSocketManager::CompleteListen,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
                     std::move(ready_cb), std::move(new_connection_cb)),
      method, callback_id_);
}

void FlossSocketManager::ListenUsingL2capLe(
    const Security security_level,
    ResponseCallback<BtifStatus> callback,
    ConnectionStateChanged ready_cb,
    ConnectionAccepted new_connection_cb) {
  if (callback_id_ == kInvalidCallbackId) {
    std::move(callback).Run(base::unexpected(Error(kErrorInvalidCallback, "")));
    return;
  }

  const char* method = security_level == Security::kInsecure
                           ? socket_manager::kListenUsingInsecureL2capLeChannel
                           : socket_manager::kListenUsingL2capLeChannel;

  CallSocketMethod(
      base::BindOnce(&FlossSocketManager::CompleteListen,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
                     std::move(ready_cb), std::move(new_connection_cb)),
      method, callback_id_);
}

void FlossSocketManager::ListenUsingRfcommAlt(
    const std::optional<std::string> name,
    const std::optional<device::BluetoothUUID> application_uuid,
    const std::optional<int> channel,
    const std::optional<int> flags,
    ResponseCallback<BtifStatus> callback,
    ConnectionStateChanged ready_cb,
    ConnectionAccepted new_connection_cb) {
  if (callback_id_ == kInvalidCallbackId) {
    std::move(callback).Run(
        base::unexpected(Error(kErrorInvalidCallback, /*message=*/"")));
    return;
  }
  CallSocketMethod(
      base::BindOnce(&FlossSocketManager::CompleteListen,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
                     std::move(ready_cb), std::move(new_connection_cb)),
      socket_manager::kListenUsingRfcomm, callback_id_, channel,
      application_uuid, name, flags);
}

void FlossSocketManager::ListenUsingRfcomm(
    const std::string& name,
    const device::BluetoothUUID& uuid,
    const Security security_level,
    ResponseCallback<BtifStatus> callback,
    ConnectionStateChanged ready_cb,
    ConnectionAccepted new_connection_cb) {
  if (callback_id_ == kInvalidCallbackId) {
    std::move(callback).Run(
        base::unexpected(Error(kErrorInvalidCallback, /*message=*/"")));
    return;
  }

  const char* method =
      security_level == Security::kInsecure
          ? socket_manager::kListenUsingInsecureRfcommWithServiceRecord
          : socket_manager::kListenUsingRfcommWithServiceRecord;
  CallSocketMethod(
      base::BindOnce(&FlossSocketManager::CompleteListen,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
                     std::move(ready_cb), std::move(new_connection_cb)),
      method, callback_id_, name, uuid);
}

void FlossSocketManager::ConnectUsingL2cap(const FlossDeviceId& remote_device,
                                           const int psm,
                                           const Security security_level,
                                           ConnectionCompleted callback) {
  if (callback_id_ == kInvalidCallbackId) {
    std::move(callback).Run(BtifStatus::kFail, /*socket=*/std::nullopt);
    return;
  }

  const char* method = security_level == Security::kInsecure
                           ? socket_manager::kCreateInsecureL2capChannel
                           : socket_manager::kCreateL2capChannel;

  CallSocketMethod(
      base::BindOnce(&FlossSocketManager::CompleteConnect,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
      method, callback_id_, remote_device, psm);
}

void FlossSocketManager::ConnectUsingL2capLe(const FlossDeviceId& remote_device,
                                             const int psm,
                                             const Security security_level,
                                             ConnectionCompleted callback) {
  if (callback_id_ == kInvalidCallbackId) {
    std::move(callback).Run(BtifStatus::kFail, /*socket=*/std::nullopt);
    return;
  }

  const char* method = security_level == Security::kInsecure
                           ? socket_manager::kCreateInsecureL2capLeChannel
                           : socket_manager::kCreateL2capLeChannel;

  CallSocketMethod(
      base::BindOnce(&FlossSocketManager::CompleteConnect,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
      method, callback_id_, remote_device, psm);
}

void FlossSocketManager::ConnectUsingRfcomm(const FlossDeviceId& remote_device,
                                            const device::BluetoothUUID& uuid,
                                            const Security security_level,
                                            ConnectionCompleted callback) {
  if (callback_id_ == kInvalidCallbackId) {
    std::move(callback).Run(BtifStatus::kFail, /*socket=*/std::nullopt);
    return;
  }

  const char* method =
      security_level == Security::kInsecure
          ? socket_manager::kCreateInsecureRfcommSocketToServiceRecord
          : socket_manager::kCreateRfcommSocketToServiceRecord;

  CallSocketMethod(
      base::BindOnce(&FlossSocketManager::CompleteConnect,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
      method, callback_id_, remote_device, uuid);
}

void FlossSocketManager::Accept(const SocketId id,
                                std::optional<uint32_t> timeout_ms,
                                ResponseCallback<BtifStatus> callback) {
  if (callback_id_ == kInvalidCallbackId) {
    std::move(callback).Run(base::unexpected(Error(kErrorInvalidCallback, "")));
    return;
  }

  CallSocketMethod(std::move(callback), socket_manager::kAccept, callback_id_,
                   id, timeout_ms);
}

void FlossSocketManager::Close(const SocketId id,
                               ResponseCallback<BtifStatus> callback) {
  if (callback_id_ == kInvalidCallbackId) {
    std::move(callback).Run(base::unexpected(Error(kErrorInvalidCallback, "")));
    return;
  }

  CallSocketMethod(std::move(callback), socket_manager::kClose, callback_id_,
                   id);
}

void FlossSocketManager::Init(dbus::Bus* bus,
                              const std::string& service_name,
                              const int adapter_index,
                              base::Version version,
                              base::OnceClosure on_ready) {
  bus_ = bus;
  service_name_ = service_name;
  adapter_path_ = GenerateAdapterPath(adapter_index);
  version_ = version;

  dbus::ObjectProxy* object_proxy =
      bus_->GetObjectProxy(service_name_, adapter_path_);
  if (!object_proxy) {
    LOG(ERROR) << "FlossSocketManager couldn't init. Object proxy was null.";
    return;
  }

  dbus::ExportedObject* callbacks =
      bus_->GetExportedObject(dbus::ObjectPath(kExportedCallbacksPath));
  if (!callbacks) {
    LOG(ERROR) << "FlossSocketManager couldn't export client callbacks.";
    return;
  }

  // Export callbacks for socket manager.
  callbacks->ExportMethod(
      socket_manager::kCallbackInterface,
      socket_manager::kOnIncomingSocketReady,
      base::BindRepeating(&FlossSocketManager::OnIncomingSocketReady,
                          weak_ptr_factory_.GetWeakPtr()),
      base::BindOnce(&HandleExported, socket_manager::kOnIncomingSocketReady));
  callbacks->ExportMethod(
      socket_manager::kCallbackInterface,
      socket_manager::kOnIncomingSocketClosed,
      base::BindRepeating(&FlossSocketManager::OnIncomingSocketClosed,
                          weak_ptr_factory_.GetWeakPtr()),
      base::BindOnce(&HandleExported, socket_manager::kOnIncomingSocketClosed));
  callbacks->ExportMethod(
      socket_manager::kCallbackInterface,
      socket_manager::kOnHandleIncomingConnection,
      base::BindRepeating(&FlossSocketManager::OnHandleIncomingConnection,
                          weak_ptr_factory_.GetWeakPtr()),
      base::BindOnce(&HandleExported,
                     socket_manager::kOnHandleIncomingConnection));
  callbacks->ExportMethod(
      socket_manager::kCallbackInterface,
      socket_manager::kOnOutgoingConnectionResult,
      base::BindRepeating(&FlossSocketManager::OnOutgoingConnectionResult,
                          weak_ptr_factory_.GetWeakPtr()),
      base::BindOnce(&HandleExported,
                     socket_manager::kOnOutgoingConnectionResult));

  // Register callbacks and store the callback id.
  dbus::MethodCall register_callback(kSocketManagerInterface,
                                     socket_manager::kRegisterCallback);
  dbus::MessageWriter writer(&register_callback);
  writer.AppendObjectPath(dbus::ObjectPath(kExportedCallbacksPath));

  object_proxy->CallMethodWithErrorResponse(
      &register_callback, kDBusTimeoutMs,
      base::BindOnce(&FlossSocketManager::CompleteRegisterCallback,
                     weak_ptr_factory_.GetWeakPtr()));

  on_ready_ = std::move(on_ready);
}

void FlossSocketManager::CompleteRegisterCallback(
    dbus::Response* response,
    dbus::ErrorResponse* error_response) {
  if (error_response) {
    FlossDBusClient::LogErrorResponse("SocketManager::RegisterCallback",
                                      error_response);
  } else {
    dbus::MessageReader reader(response);
    uint32_t result;
    if (!reader.PopUint32(&result)) {
      LOG(ERROR)
          << "No callback id provided for SocketManager::RegisterCallback";
      return;
    }

    callback_id_ = result;

    if (on_ready_) {
      std::move(on_ready_).Run();
    }
  }
}

void FlossSocketManager::CompleteUnregisterCallback(DBusResult<bool> result) {
  if (!result.has_value() || *result == false) {
    LOG(WARNING) << __func__ << ": Failed to unregister callback";
  }
}

void FlossSocketManager::CompleteListen(ResponseCallback<BtifStatus> callback,
                                        ConnectionStateChanged ready_cb,
                                        ConnectionAccepted new_connection_cb,
                                        DBusResult<SocketResult> result) {
  if (!result.has_value()) {
    std::move(callback).Run(base::unexpected(result.error()));
    return;
  }

  // We got back a valid socket id from listen. Put into listening list.
  if (result->id != kInvalidSocketId) {
    listening_sockets_to_callbacks_.insert({
        result->id,
        {std::move(ready_cb), std::move(new_connection_cb)},
    });
  }

  // Complete callback with the BtifStatus.
  std::move(callback).Run(result->status);
}

void FlossSocketManager::CompleteConnect(ConnectionCompleted callback,
                                         DBusResult<SocketResult> result) {
  if (!result.has_value()) {
    std::move(callback).Run(BtifStatus::kFail, /*socket=*/std::nullopt);
    return;
  }

  // If we got back a valid socket id from connect, put into connecting list.
  // Otherwise, return the failed status back upwards.
  if (result->id != kInvalidSocketId) {
    connecting_sockets_to_callbacks_.insert({
        result->id,
        std::move(callback),
    });
  } else {
    std::move(callback).Run(result->status, /*socket=*/std::nullopt);
  }
}

void FlossSocketManager::OnIncomingSocketReady(
    dbus::MethodCall* method_call,
    dbus::ExportedObject::ResponseSender response_sender) {
  dbus::MessageReader reader(method_call);
  FlossListeningSocket socket;
  BtifStatus status;

  if (!ReadAllDBusParams(&reader, &socket, &status)) {
    std::move(response_sender)
        .Run(dbus::ErrorResponse::FromMethodCall(
            method_call, kErrorInvalidParameters, std::string()));
    return;
  }

  // If this is a known socket, run the |ConnectionStateChanged| callback.
  auto found = listening_sockets_to_callbacks_.find(socket.id);
  if (found != listening_sockets_to_callbacks_.end()) {
    auto& [key, callbacks] = *found;
    auto& [state_changed, accepted] = callbacks;

    state_changed.Run(ServerSocketState::kReady, socket, status);
  }

  std::move(response_sender).Run(dbus::Response::FromMethodCall(method_call));
}

void FlossSocketManager::OnIncomingSocketClosed(
    dbus::MethodCall* method_call,
    dbus::ExportedObject::ResponseSender response_sender) {
  dbus::MessageReader reader(method_call);
  SocketId id;
  BtifStatus status;

  if (!ReadAllDBusParams(&reader, &id, &status)) {
    std::move(response_sender)
        .Run(dbus::ErrorResponse::FromMethodCall(
            method_call, kErrorInvalidParameters, std::string()));
    return;
  }

  // If this is a known socket, run the |ConnectionStateChanged| callback and
  // remove this from the list of listening sockets.
  auto found = listening_sockets_to_callbacks_.find(id);
  if (found != listening_sockets_to_callbacks_.end()) {
    FlossListeningSocket socket;
    socket.id = id;

    auto& [key, callbacks] = *found;
    auto& [state_changed, accepted] = callbacks;

    state_changed.Run(ServerSocketState::kClosed, socket, status);
    listening_sockets_to_callbacks_.erase(found);
  }

  std::move(response_sender).Run(dbus::Response::FromMethodCall(method_call));
}

void FlossSocketManager::OnHandleIncomingConnection(
    dbus::MethodCall* method_call,
    dbus::ExportedObject::ResponseSender response_sender) {
  dbus::MessageReader reader(method_call);
  SocketId id;
  FlossSocket socket;

  if (!ReadAllDBusParams(&reader, &id, &socket)) {
    std::move(response_sender)
        .Run(dbus::ErrorResponse::FromMethodCall(
            method_call, kErrorInvalidParameters, std::string()));
    return;
  }

  // New connection on a known listening socket. Call the |ConnectionAccepted|
  // callback.
  auto found = listening_sockets_to_callbacks_.find(id);
  if (found != listening_sockets_to_callbacks_.end()) {
    auto& [key, callbacks] = *found;
    auto& [state_changed, accepted] = callbacks;

    accepted.Run(std::move(socket));
  }

  std::move(response_sender).Run(dbus::Response::FromMethodCall(method_call));
}

void FlossSocketManager::OnOutgoingConnectionResult(
    dbus::MethodCall* method_call,
    dbus::ExportedObject::ResponseSender response_sender) {
  dbus::MessageReader reader(method_call);
  SocketId id;
  BtifStatus status;
  std::optional<FlossSocket> socket;

  if (!ReadAllDBusParams(&reader, &id, &status, &socket)) {
    std::move(response_sender)
        .Run(dbus::ErrorResponse::FromMethodCall(
            method_call, kErrorInvalidParameters, std::string()));
    return;
  }

  // Connecting callback finished. Call the |ConnectionCompleted| callback and
  // remove this entry from the pending connections list.
  auto found = connecting_sockets_to_callbacks_.find(id);
  if (found != connecting_sockets_to_callbacks_.end()) {
    auto& [key, complete_callback] = *found;
    std::move(complete_callback).Run(status, std::move(socket));
    connecting_sockets_to_callbacks_.erase(found);
  }

  std::move(response_sender).Run(dbus::Response::FromMethodCall(method_call));
}

// Specializations for default responses.
template void FlossDBusClient::DefaultResponseWithCallback(
    ResponseCallback<FlossSocketManager::SocketResult> callback,
    dbus::Response* response,
    dbus::ErrorResponse* error_response);

}  // namespace floss