| Index: device/bluetooth/bluetooth_socket_mac.mm
|
| diff --git a/device/bluetooth/bluetooth_socket_mac.mm b/device/bluetooth/bluetooth_socket_mac.mm
|
| index a6934304205a557a11ab7fd448b05c64196cf383..67fb94903160914bc57de189b17501a361a940be 100644
|
| --- a/device/bluetooth/bluetooth_socket_mac.mm
|
| +++ b/device/bluetooth/bluetooth_socket_mac.mm
|
| @@ -21,8 +21,10 @@
|
| #include "base/strings/sys_string_conversions.h"
|
| #include "base/threading/thread_restrictions.h"
|
| #include "device/bluetooth/bluetooth_adapter.h"
|
| +#include "device/bluetooth/bluetooth_channel_mac.h"
|
| #include "device/bluetooth/bluetooth_device.h"
|
| #include "device/bluetooth/bluetooth_device_mac.h"
|
| +#include "device/bluetooth/bluetooth_rfcomm_channel_mac.h"
|
| #include "net/base/io_buffer.h"
|
| #include "net/base/net_errors.h"
|
|
|
| @@ -141,51 +143,8 @@ using device::BluetoothSocket;
|
| return;
|
| }
|
|
|
| - socket_->OnRfcommChannelOpened(rfcommChannel);
|
| -}
|
| -
|
| -@end
|
| -
|
| -// A simple delegate class for an open RFCOMM channel that forwards methods to
|
| -// its wrapped |socket_|.
|
| -@interface BluetoothRfcommChannelDelegate
|
| - : NSObject <IOBluetoothRFCOMMChannelDelegate> {
|
| - @private
|
| - device::BluetoothSocketMac* socket_; // weak
|
| -}
|
| -
|
| -- (id)initWithSocket:(device::BluetoothSocketMac*)socket;
|
| -
|
| -@end
|
| -
|
| -@implementation BluetoothRfcommChannelDelegate
|
| -
|
| -- (id)initWithSocket:(device::BluetoothSocketMac*)socket {
|
| - if ((self = [super init]))
|
| - socket_ = socket;
|
| -
|
| - return self;
|
| -}
|
| -
|
| -- (void)rfcommChannelOpenComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel
|
| - status:(IOReturn)error {
|
| - socket_->OnRfcommChannelOpenComplete(rfcommChannel, error);
|
| -}
|
| -
|
| -- (void)rfcommChannelWriteComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel
|
| - refcon:(void*)refcon
|
| - status:(IOReturn)error {
|
| - socket_->OnRfcommChannelWriteComplete(rfcommChannel, refcon, error);
|
| -}
|
| -
|
| -- (void)rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel
|
| - data:(void*)dataPointer
|
| - length:(size_t)dataLength {
|
| - socket_->OnRfcommChannelDataReceived(rfcommChannel, dataPointer, dataLength);
|
| -}
|
| -
|
| -- (void)rfcommChannelClosed:(IOBluetoothRFCOMMChannel*)rfcommChannel {
|
| - socket_->OnRfcommChannelClosed(rfcommChannel);
|
| + socket_->OnChannelOpened(scoped_ptr<device::BluetoothChannelMac>(
|
| + new device::BluetoothRfcommChannelMac(NULL, [rfcommChannel retain])));
|
| }
|
|
|
| @end
|
| @@ -336,8 +295,8 @@ void BluetoothSocketMac::Connect(
|
| // Perform an SDP query on the |device| to refresh the cache, in case the
|
| // services that the |device| advertises have changed since the previous
|
| // query.
|
| - VLOG(1) << BluetoothDeviceMac::GetDeviceAddress(device) << " "
|
| - << uuid_.canonical_value() << ": Sending SDP query.";
|
| + DVLOG(1) << BluetoothDeviceMac::GetDeviceAddress(device) << " "
|
| + << uuid_.canonical_value() << ": Sending SDP query.";
|
| SDPQueryListener* listener =
|
| [[SDPQueryListener alloc] initWithSocket:this
|
| device:device
|
| @@ -358,7 +317,7 @@ void BluetoothSocketMac::ListenUsingRfcomm(
|
| adapter_ = adapter;
|
| uuid_ = uuid;
|
|
|
| - VLOG(1) << uuid_.canonical_value() << ": Registering service.";
|
| + DVLOG(1) << uuid_.canonical_value() << ": Registering service.";
|
| BluetoothRFCOMMChannelID registered_channel_id;
|
| service_record_handle_ =
|
| RegisterRfcommService(uuid, channel_id, ®istered_channel_id);
|
| @@ -391,8 +350,8 @@ void BluetoothSocketMac::OnSDPQueryComplete(
|
| const base::Closure& success_callback,
|
| const ErrorCompletionCallback& error_callback) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - VLOG(1) << BluetoothDeviceMac::GetDeviceAddress(device) << " "
|
| - << uuid_.canonical_value() << ": SDP query complete.";
|
| + DVLOG(1) << BluetoothDeviceMac::GetDeviceAddress(device) << " "
|
| + << uuid_.canonical_value() << ": SDP query complete.";
|
|
|
| if (status != kIOReturnSuccess) {
|
| error_callback.Run(kSDPQueryFailed);
|
| @@ -411,7 +370,7 @@ void BluetoothSocketMac::OnSDPQueryComplete(
|
| return;
|
| }
|
|
|
| - if (rfcomm_channel_) {
|
| + if (channel_) {
|
| error_callback.Run(kSocketAlreadyConnected);
|
| return;
|
| }
|
| @@ -424,24 +383,19 @@ void BluetoothSocketMac::OnSDPQueryComplete(
|
| return;
|
| }
|
|
|
| - VLOG(1) << BluetoothDeviceMac::GetDeviceAddress(device) << " "
|
| - << uuid_.canonical_value() << ": Opening RFCOMM channel: "
|
| - << rfcomm_channel_id;
|
| + DVLOG(1) << BluetoothDeviceMac::GetDeviceAddress(device) << " "
|
| + << uuid_.canonical_value() << ": Opening RFCOMM channel: "
|
| + << rfcomm_channel_id;
|
|
|
| // Note: It's important to set the connect callbacks *prior* to opening the
|
| // channel as the delegate is passed in and can synchronously call into
|
| - // OnRfcommChannelOpenComplete().
|
| + // OnChannelOpenComplete().
|
| connect_callbacks_.reset(new ConnectCallbacks());
|
| connect_callbacks_->success_callback = success_callback;
|
| connect_callbacks_->error_callback = error_callback;
|
|
|
| - rfcomm_channel_delegate_.reset(
|
| - [[BluetoothRfcommChannelDelegate alloc] initWithSocket:this]);
|
| -
|
| - IOBluetoothRFCOMMChannel* rfcomm_channel;
|
| - status = [device openRFCOMMChannelAsync:&rfcomm_channel
|
| - withChannelID:rfcomm_channel_id
|
| - delegate:rfcomm_channel_delegate_];
|
| + channel_ = BluetoothRfcommChannelMac::OpenAsync(
|
| + this, device, rfcomm_channel_id, &status);
|
| if (status != kIOReturnSuccess) {
|
| std::stringstream error;
|
| error << "Failed to connect bluetooth socket ("
|
| @@ -451,22 +405,17 @@ void BluetoothSocketMac::OnSDPQueryComplete(
|
| return;
|
| }
|
|
|
| - VLOG(2) << BluetoothDeviceMac::GetDeviceAddress(device) << " "
|
| - << uuid_.canonical_value()
|
| - << ": RFCOMM channel opening in background.";
|
| - rfcomm_channel_.reset([rfcomm_channel retain]);
|
| + DVLOG(2) << BluetoothDeviceMac::GetDeviceAddress(device) << " "
|
| + << uuid_.canonical_value()
|
| + << ": RFCOMM channel opening in background.";
|
| }
|
|
|
| -void BluetoothSocketMac::OnRfcommChannelOpened(
|
| - IOBluetoothRFCOMMChannel* rfcomm_channel) {
|
| +void BluetoothSocketMac::OnChannelOpened(
|
| + scoped_ptr<BluetoothChannelMac> channel) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - VLOG(1) << uuid_.canonical_value() << ": Incoming RFCOMM channel pending.";
|
| + DVLOG(1) << uuid_.canonical_value() << ": Incoming channel pending.";
|
|
|
| - // TODO(isherman): The channel ought to already be retained. Stop
|
| - // over-retaining it.
|
| - base::scoped_nsobject<IOBluetoothRFCOMMChannel>
|
| - scoped_channel([rfcomm_channel retain]);
|
| - accept_queue_.push(scoped_channel);
|
| + accept_queue_.push(linked_ptr<BluetoothChannelMac>(channel.release()));
|
| if (accept_request_)
|
| AcceptConnectionRequest();
|
|
|
| @@ -483,33 +432,21 @@ void BluetoothSocketMac::OnRfcommChannelOpened(
|
| // http://crbug.com/367319
|
| }
|
|
|
| -void BluetoothSocketMac::OnRfcommChannelOpenComplete(
|
| - IOBluetoothRFCOMMChannel* rfcomm_channel,
|
| +void BluetoothSocketMac::OnChannelOpenComplete(
|
| + const std::string& device_address,
|
| IOReturn status) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - // TODO(isherman): Come back to these DCHECKs -- I'm not completely convinced
|
| - // that they're correct.
|
| - if (rfcomm_channel_) {
|
| - // Client connection complete.
|
| - DCHECK_EQ(rfcomm_channel_, rfcomm_channel);
|
| - DCHECK(is_connecting());
|
| - } else {
|
| - // A new client has connected to this server socket.
|
| - DCHECK_EQ(kIOReturnSuccess, status);
|
| - }
|
| -
|
| - VLOG(1) << BluetoothDeviceMac::GetDeviceAddress([rfcomm_channel getDevice])
|
| - << " " << uuid_.canonical_value()
|
| - << ": RFCOMM channel open complete.";
|
| + DCHECK(is_connecting());
|
|
|
| + DVLOG(1) << device_address << " " << uuid_.canonical_value()
|
| + << ": channel open complete.";
|
|
|
| scoped_ptr<ConnectCallbacks> temp = connect_callbacks_.Pass();
|
| if (status != kIOReturnSuccess) {
|
| ReleaseChannel();
|
| std::stringstream error;
|
| - error << "Failed to connect bluetooth socket ("
|
| - << BluetoothDeviceMac::GetDeviceAddress([rfcomm_channel getDevice])
|
| - << "): (" << status << ")";
|
| + error << "Failed to connect bluetooth socket (" << device_address << "): ("
|
| + << status << ")";
|
| temp->error_callback.Run(error.str());
|
| return;
|
| }
|
| @@ -520,7 +457,7 @@ void BluetoothSocketMac::OnRfcommChannelOpenComplete(
|
| void BluetoothSocketMac::Close() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| - if (rfcomm_channel_)
|
| + if (channel_)
|
| ReleaseChannel();
|
| else if (service_record_handle_ != kInvalidServiceRecordHandle)
|
| ReleaseListener();
|
| @@ -544,7 +481,7 @@ void BluetoothSocketMac::Receive(
|
| return;
|
| }
|
|
|
| - if (!rfcomm_channel_) {
|
| + if (!channel_) {
|
| error_callback.Run(BluetoothSocket::kDisconnected, kSocketNotConnected);
|
| return;
|
| }
|
| @@ -569,12 +506,10 @@ void BluetoothSocketMac::Receive(
|
| receive_callbacks_->error_callback = error_callback;
|
| }
|
|
|
| -void BluetoothSocketMac::OnRfcommChannelDataReceived(
|
| - IOBluetoothRFCOMMChannel* rfcomm_channel,
|
| +void BluetoothSocketMac::OnChannelDataReceived(
|
| void* data,
|
| size_t length) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - DCHECK_EQ(rfcomm_channel_, rfcomm_channel);
|
| DCHECK(!is_connecting());
|
|
|
| int data_size = base::checked_cast<int>(length);
|
| @@ -604,7 +539,7 @@ void BluetoothSocketMac::Send(scoped_refptr<net::IOBuffer> buffer,
|
| return;
|
| }
|
|
|
| - if (!rfcomm_channel_) {
|
| + if (!channel_) {
|
| error_callback.Run(kSocketNotConnected);
|
| return;
|
| }
|
| @@ -618,21 +553,20 @@ void BluetoothSocketMac::Send(scoped_refptr<net::IOBuffer> buffer,
|
|
|
| // |writeAsync| accepts buffers of max. mtu bytes per call, so we need to emit
|
| // multiple write operations if buffer_size > mtu.
|
| - BluetoothRFCOMMMTU mtu = [rfcomm_channel_ getMTU];
|
| + uint16_t mtu = channel_->GetOutgoingMTU();
|
| scoped_refptr<net::DrainableIOBuffer> send_buffer(
|
| new net::DrainableIOBuffer(buffer, buffer_size));
|
| while (send_buffer->BytesRemaining() > 0) {
|
| int byte_count = send_buffer->BytesRemaining();
|
| if (byte_count > mtu)
|
| byte_count = mtu;
|
| - IOReturn status = [rfcomm_channel_ writeAsync:send_buffer->data()
|
| - length:byte_count
|
| - refcon:request.get()];
|
| + IOReturn status =
|
| + channel_->WriteAsync(send_buffer->data(), byte_count, request.get());
|
| +
|
| if (status != kIOReturnSuccess) {
|
| std::stringstream error;
|
| error << "Failed to connect bluetooth socket ("
|
| - << BluetoothDeviceMac::GetDeviceAddress([rfcomm_channel_ getDevice])
|
| - << "): (" << status << ")";
|
| + << channel_->GetDeviceAddress() << "): (" << status << ")";
|
| // Remember the first error only
|
| if (request->status == kIOReturnSuccess)
|
| request->status = status;
|
| @@ -652,16 +586,12 @@ void BluetoothSocketMac::Send(scoped_refptr<net::IOBuffer> buffer,
|
| }
|
| }
|
|
|
| -void BluetoothSocketMac::OnRfcommChannelWriteComplete(
|
| - IOBluetoothRFCOMMChannel* rfcomm_channel,
|
| - void* refcon,
|
| - IOReturn status) {
|
| +void BluetoothSocketMac::OnChannelWriteComplete(void* refcon, IOReturn status) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| // Note: We use "CHECK" below to ensure we never run into unforeseen
|
| // occurrences of asynchronous callbacks, which could lead to data
|
| // corruption.
|
| - CHECK_EQ(rfcomm_channel_, rfcomm_channel);
|
| CHECK_EQ(static_cast<SendRequest*>(refcon), send_queue_.front().get());
|
|
|
| // Keep a local linked_ptr to avoid releasing the request too early if we end
|
| @@ -686,8 +616,7 @@ void BluetoothSocketMac::OnRfcommChannelWriteComplete(
|
| if (!request->error_signaled) {
|
| std::stringstream error;
|
| error << "Failed to connect bluetooth socket ("
|
| - << BluetoothDeviceMac::GetDeviceAddress([rfcomm_channel_ getDevice])
|
| - << "): (" << status << ")";
|
| + << channel_->GetDeviceAddress() << "): (" << status << ")";
|
| request->error_signaled = true;
|
| request->error_callback.Run(error.str());
|
| }
|
| @@ -696,10 +625,8 @@ void BluetoothSocketMac::OnRfcommChannelWriteComplete(
|
| }
|
| }
|
|
|
| -void BluetoothSocketMac::OnRfcommChannelClosed(
|
| - IOBluetoothRFCOMMChannel* rfcomm_channel) {
|
| +void BluetoothSocketMac::OnChannelClosed() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - DCHECK_EQ(rfcomm_channel_, rfcomm_channel);
|
|
|
| if (receive_callbacks_) {
|
| scoped_ptr<ReceiveCallbacks> temp = receive_callbacks_.Pass();
|
| @@ -731,41 +658,36 @@ void BluetoothSocketMac::Accept(
|
|
|
| void BluetoothSocketMac::AcceptConnectionRequest() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - VLOG(1) << uuid_.canonical_value() << ": Accepting pending connection.";
|
| + DVLOG(1) << uuid_.canonical_value() << ": Accepting pending connection.";
|
|
|
| - base::scoped_nsobject<IOBluetoothRFCOMMChannel> rfcomm_channel =
|
| - accept_queue_.front();
|
| + linked_ptr<BluetoothChannelMac> channel = accept_queue_.front();
|
| + accept_queue_.pop();
|
|
|
| // TODO(isherman): Is it actually guaranteed that the device is still
|
| // connected at this point?
|
| - BluetoothDevice* device = adapter_->GetDevice(
|
| - BluetoothDeviceMac::GetDeviceAddress([rfcomm_channel getDevice]));
|
| + BluetoothDevice* device = adapter_->GetDevice(channel->GetDeviceAddress());
|
| DCHECK(device);
|
|
|
| scoped_refptr<BluetoothSocketMac> client_socket =
|
| BluetoothSocketMac::CreateSocket();
|
|
|
| client_socket->uuid_ = uuid_;
|
| - client_socket->rfcomm_channel_.reset([rfcomm_channel retain]);
|
| - client_socket->rfcomm_channel_delegate_.reset(
|
| - [[BluetoothRfcommChannelDelegate alloc] initWithSocket:client_socket]);
|
| + client_socket->channel_.reset(channel.release());
|
|
|
| - // Setting the delegate will cause the delegate method for open complete
|
| - // to be called on the new socket. Set the new socket to be connecting and
|
| - // hook it up to run the accept callback with the device object.
|
| + // Associating the socket can synchronously call into OnChannelOpenComplete().
|
| + // Make sure to first set the new socket to be connecting and hook it up to
|
| + // run the accept callback with the device object.
|
| client_socket->connect_callbacks_.reset(new ConnectCallbacks());
|
| client_socket->connect_callbacks_->success_callback =
|
| base::Bind(accept_request_->success_callback, device, client_socket);
|
| client_socket->connect_callbacks_->error_callback =
|
| accept_request_->error_callback;
|
| -
|
| - [client_socket->rfcomm_channel_
|
| - setDelegate:client_socket->rfcomm_channel_delegate_];
|
| -
|
| accept_request_.reset();
|
| - accept_queue_.pop();
|
|
|
| - VLOG(1) << uuid_.canonical_value() << ": Accept complete.";
|
| + // Now it's safe to associate the socket with the channel.
|
| + client_socket->channel_->SetSocket(client_socket.get());
|
| +
|
| + DVLOG(1) << uuid_.canonical_value() << ": Accept complete.";
|
| }
|
|
|
| BluetoothSocketMac::AcceptRequest::AcceptRequest() {}
|
| @@ -791,18 +713,13 @@ BluetoothSocketMac::BluetoothSocketMac()
|
|
|
| BluetoothSocketMac::~BluetoothSocketMac() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - DCHECK(!rfcomm_channel_);
|
| + DCHECK(!channel_);
|
| DCHECK(!rfcomm_connection_listener_);
|
| }
|
|
|
| void BluetoothSocketMac::ReleaseChannel() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - if (rfcomm_channel_) {
|
| - [rfcomm_channel_ setDelegate:nil];
|
| - [rfcomm_channel_ closeChannel];
|
| - rfcomm_channel_.reset();
|
| - rfcomm_channel_delegate_.reset();
|
| - }
|
| + channel_.reset();
|
|
|
| // Closing the channel above prevents the callback delegate from being called
|
| // so it is now safe to release all callback state.
|
| @@ -818,6 +735,11 @@ void BluetoothSocketMac::ReleaseListener() {
|
|
|
| IOBluetoothRemoveServiceWithRecordHandle(service_record_handle_);
|
| rfcomm_connection_listener_.reset();
|
| +
|
| + // Destroying the listener above prevents the callback delegate from being
|
| + // called so it is now safe to release all callback state.
|
| + accept_request_.reset();
|
| + empty_queue(accept_queue_);
|
| }
|
|
|
| } // namespace device
|
|
|