// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_MAC_H_
#define DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_MAC_H_
#include <queue>
#include <string>
#import <IOBluetooth/IOBluetooth.h>
#import <IOKit/IOReturn.h>
#include "base/mac/scoped_nsobject.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/thread_checker.h"
#include "device/bluetooth/bluetooth_socket.h"
#include "device/bluetooth/bluetooth_uuid.h"
@class BluetoothRfcommConnectionListener;
@class BluetoothL2capConnectionListener;
namespace net {
class IOBuffer;
class IOBufferWithSize;
}
namespace device {
class BluetoothAdapterMac;
class BluetoothChannelMac;
// Implements the BluetoothSocket class for the Mac OS X platform.
class BluetoothSocketMac : public BluetoothSocket {
public:
static scoped_refptr<BluetoothSocketMac> CreateSocket();
// Connects this socket to the service on |device| published as UUID |uuid|.
// The underlying protocol and PSM or Channel is obtained through service
// discovery. On a successful connection, the socket properties will be
// updated and |success_callback| called. On failure, |error_callback| will be
// called with a message explaining the cause of failure.
void Connect(IOBluetoothDevice* device,
const BluetoothUUID& uuid,
const base::Closure& success_callback,
const ErrorCompletionCallback& error_callback);
// Listens for incoming RFCOMM connections using this socket: Publishes an
// RFCOMM service on the |adapter| as UUID |uuid| with Channel |channel_id|.
// |success_callback| will be called if the service is successfully
// registered, |error_callback| on failure with a message explaining the
// cause.
void ListenUsingRfcomm(scoped_refptr<BluetoothAdapterMac> adapter,
const BluetoothUUID& uuid,
int channel_id,
const base::Closure& success_callback,
const ErrorCompletionCallback& error_callback);
// Listens for incoming L2CAP connections using this socket: Publishes an
// L2CAP service on the |adapter| as UUID |uuid| with PSM |psm|.
// |success_callback| will be called if the service is successfully
// registered, |error_callback| on failure with a message explaining the
// cause.
void ListenUsingL2cap(scoped_refptr<BluetoothAdapterMac> adapter,
const BluetoothUUID& uuid,
int psm,
const base::Closure& success_callback,
const ErrorCompletionCallback& error_callback);
// BluetoothSocket:
virtual void Close() OVERRIDE;
virtual void Disconnect(const base::Closure& callback) OVERRIDE;
virtual void Receive(
int /* buffer_size */,
const ReceiveCompletionCallback& success_callback,
const ReceiveErrorCompletionCallback& error_callback) OVERRIDE;
virtual void Send(scoped_refptr<net::IOBuffer> buffer,
int buffer_size,
const SendCompletionCallback& success_callback,
const ErrorCompletionCallback& error_callback) OVERRIDE;
virtual void Accept(const AcceptCompletionCallback& success_callback,
const ErrorCompletionCallback& error_callback) OVERRIDE;
// Callback that is invoked when the OS completes an SDP query.
// |status| is the returned status from the SDP query, |device| is the
// IOBluetoothDevice for which the query was made. The remaining
// parameters are those from |Connect()|.
void OnSDPQueryComplete(
IOReturn status,
IOBluetoothDevice* device,
const base::Closure& success_callback,
const ErrorCompletionCallback& error_callback);
// Called by BluetoothRfcommConnectionListener and
// BluetoothL2capConnectionListener.
void OnChannelOpened(scoped_ptr<BluetoothChannelMac> channel);
// Called by |channel_|.
// Note: OnChannelOpenComplete might be called before the |channel_| is set.
void OnChannelOpenComplete(const std::string& device_address,
IOReturn status);
void OnChannelClosed();
void OnChannelDataReceived(void* data, size_t length);
void OnChannelWriteComplete(void* refcon, IOReturn status);
private:
struct AcceptRequest {
AcceptRequest();
~AcceptRequest();
AcceptCompletionCallback success_callback;
ErrorCompletionCallback error_callback;
};
struct SendRequest {
SendRequest();
~SendRequest();
int buffer_size;
SendCompletionCallback success_callback;
ErrorCompletionCallback error_callback;
IOReturn status;
int active_async_writes;
bool error_signaled;
};
struct ReceiveCallbacks {
ReceiveCallbacks();
~ReceiveCallbacks();
ReceiveCompletionCallback success_callback;
ReceiveErrorCompletionCallback error_callback;
};
struct ConnectCallbacks {
ConnectCallbacks();
~ConnectCallbacks();
base::Closure success_callback;
ErrorCompletionCallback error_callback;
};
BluetoothSocketMac();
virtual ~BluetoothSocketMac();
// Accepts a single incoming connection.
void AcceptConnectionRequest();
void ReleaseChannel();
void ReleaseListener();
bool is_connecting() const { return connect_callbacks_; }
// Used to verify that all methods are called on the same thread.
base::ThreadChecker thread_checker_;
// Adapter the socket is registered against. This is only present when the
// socket is listening.
scoped_refptr<BluetoothAdapterMac> adapter_;
// UUID of the profile being connected to, or that the socket is listening on.
device::BluetoothUUID uuid_;
// Simple helpers that register for OS notifications and forward them to
// |this| profile.
base::scoped_nsobject<BluetoothRfcommConnectionListener>
rfcomm_connection_listener_;
base::scoped_nsobject<BluetoothL2capConnectionListener>
l2cap_connection_listener_;
// A handle to the service record registered in the system SDP server.
// Used to eventually unregister the service.
BluetoothSDPServiceRecordHandle service_record_handle_;
// The channel used to issue commands.
scoped_ptr<BluetoothChannelMac> channel_;
// Connection callbacks -- when a pending async connection is active.
scoped_ptr<ConnectCallbacks> connect_callbacks_;
// Packets received while there is no pending "receive" callback.
std::queue<scoped_refptr<net::IOBufferWithSize> > receive_queue_;
// Receive callbacks -- when a receive call is active.
scoped_ptr<ReceiveCallbacks> receive_callbacks_;
// Send queue -- one entry per pending send operation.
std::queue<linked_ptr<SendRequest>> send_queue_;
// The pending request to an Accept() call, or null if there is no pending
// request.
scoped_ptr<AcceptRequest> accept_request_;
// Queue of incoming connections.
std::queue<linked_ptr<BluetoothChannelMac>> accept_queue_;
DISALLOW_COPY_AND_ASSIGN(BluetoothSocketMac);
};
} // namespace device
#endif // DEVICE_BLUETOOTH_BLUETOOTH_SOCKET_MAC_H_