#ifndef DEVICE_BLUETOOTH_FLOSS_FLOSS_SOCKET_MANAGER_H_
#define DEVICE_BLUETOOTH_FLOSS_FLOSS_SOCKET_MANAGER_H_
#include <memory>
#include <string>
#include <unordered_map>
#include "base/files/scoped_file.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "dbus/exported_object.h"
#include "dbus/object_path.h"
#include "device/bluetooth/bluetooth_export.h"
#include "device/bluetooth/floss/floss_dbus_client.h"
#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
namespace floss {
class DEVICE_BLUETOOTH_EXPORT FlossSocketManager : public FlossDBusClient {
public:
using CallbackId = uint32_t;
using SocketId = uint64_t;
enum class SocketType {
kUnknown = 0,
kRfcomm = 1,
kSco_DONOTUSE = 2,
kL2cap = 3,
kL2capLe = 4,
};
enum class ServerSocketState {
kReady,
kClosed,
};
enum class Security {
kInsecure,
kSecure,
};
enum class SocketFlags : int {
kSocketFlagsEncrypt = 1 << 0,
kSocketFlagsAuth = 1 << 1,
kSocketFlagsNoSdp = 1 << 2,
kSocketFlagsAuthMitm = 1 << 3,
kSocketFlagsAuth16Digit = 1 << 4
};
static int GetRawFlossFlagsFromBluetoothFlags(bool encrypt,
bool auth,
bool auth_mitm,
bool auth_16_digit,
bool no_sdp);
struct FlossListeningSocket {
SocketId id = FlossSocketManager::kInvalidSocketId;
SocketType type = SocketType::kUnknown;
int flags = 0;
std::optional<int> psm;
std::optional<int> channel;
std::optional<std::string> name;
std::optional<device::BluetoothUUID> uuid;
FlossListeningSocket();
FlossListeningSocket(const FlossListeningSocket&);
~FlossListeningSocket();
bool is_valid() const { return id != FlossSocketManager::kInvalidSocketId; }
};
struct FlossSocket {
SocketId id = FlossSocketManager::kInvalidSocketId;
FlossDeviceId remote_device;
SocketType type = SocketType::kUnknown;
int flags = 0;
std::optional<base::ScopedFD> fd;
int port = 0;
std::optional<device::BluetoothUUID> uuid;
int max_rx_size = 0;
int max_tx_size = 0;
FlossSocket();
~FlossSocket();
FlossSocket(const FlossSocket&) = delete;
FlossSocket& operator=(const FlossSocket&) = delete;
FlossSocket(FlossSocket&&);
FlossSocket& operator=(FlossSocket&&) = default;
bool is_valid() const { return id != FlossSocketManager::kInvalidSocketId; }
};
struct SocketResult {
BtifStatus status;
SocketId id;
};
using ConnectionStateChanged = base::RepeatingCallback<
void(ServerSocketState, FlossListeningSocket, BtifStatus)>;
using ConnectionAccepted = base::RepeatingCallback<void(FlossSocket&&)>;
using ConnectionCompleted =
base::OnceCallback<void(BtifStatus, std::optional<FlossSocket>&&)>;
static const char kErrorInvalidCallback[];
static const CallbackId kInvalidCallbackId = 0;
static const SocketId kInvalidSocketId = 0;
static std::unique_ptr<FlossSocketManager> Create();
FlossSocketManager(const FlossSocketManager&) = delete;
FlossSocketManager& operator=(const FlossSocketManager&) = delete;
FlossSocketManager();
~FlossSocketManager() override;
virtual void ListenUsingL2cap(const Security security_level,
ResponseCallback<BtifStatus> callback,
ConnectionStateChanged ready_cb,
ConnectionAccepted new_connection_cb);
virtual void ListenUsingL2capLe(const Security security_level,
ResponseCallback<BtifStatus> callback,
ConnectionStateChanged ready_cb,
ConnectionAccepted new_connection_cb);
virtual void 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);
virtual void ListenUsingRfcomm(const std::string& name,
const device::BluetoothUUID& uuid,
const Security security_level,
ResponseCallback<BtifStatus> callback,
ConnectionStateChanged ready_cb,
ConnectionAccepted new_connection_cb);
virtual void ConnectUsingL2cap(const FlossDeviceId& remote_device,
const int psm,
const Security security_level,
ConnectionCompleted callback);
virtual void ConnectUsingL2capLe(const FlossDeviceId& remote_device,
const int psm,
const Security security_level,
ConnectionCompleted callback);
virtual void ConnectUsingRfcomm(const FlossDeviceId& remote_device,
const device::BluetoothUUID& uuid,
const Security security_level,
ConnectionCompleted callback);
virtual void Accept(const SocketId id,
std::optional<uint32_t> timeout_ms,
ResponseCallback<BtifStatus> callback);
virtual void Close(const SocketId id, ResponseCallback<BtifStatus> callback);
void Init(dbus::Bus* bus,
const std::string& service_name,
const int adapter_index,
base::Version version,
base::OnceClosure on_ready) override;
protected:
friend class FlossSocketManagerTest;
void CompleteRegisterCallback(dbus::Response* response,
dbus::ErrorResponse* error_response);
void CompleteUnregisterCallback(DBusResult<bool> result);
void CompleteListen(ResponseCallback<BtifStatus> callback,
ConnectionStateChanged ready_cb,
ConnectionAccepted new_connection_cb,
DBusResult<SocketResult> result);
void CompleteConnect(ConnectionCompleted callback,
DBusResult<SocketResult> result);
void OnIncomingSocketReady(
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender);
void OnIncomingSocketClosed(
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender);
void OnHandleIncomingConnection(
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender);
void OnOutgoingConnectionResult(
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender);
raw_ptr<dbus::Bus> bus_ = nullptr;
dbus::ObjectPath adapter_path_;
std::string service_name_;
std::unordered_map<SocketId,
std::pair<ConnectionStateChanged, ConnectionAccepted>>
listening_sockets_to_callbacks_;
std::unordered_map<SocketId, ConnectionCompleted>
connecting_sockets_to_callbacks_;
private:
template <typename R, typename... Args>
void CallSocketMethod(ResponseCallback<R> callback,
const char* member,
Args... args) {
CallMethod(std::move(callback), bus_, service_name_,
kSocketManagerInterface, adapter_path_, member, args...);
}
static const char kExportedCallbacksPath[];
CallbackId callback_id_ = kInvalidCallbackId;
base::OnceClosure on_ready_;
base::WeakPtrFactory<FlossSocketManager> weak_ptr_factory_{this};
};
}
#endif