diff options
author | isherman@chromium.org <isherman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-12 12:59:20 +0000 |
---|---|---|
committer | isherman@chromium.org <isherman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-12 12:59:20 +0000 |
commit | 8696f577d5cb8198d7ffa5939d4fb537282ca7c2 (patch) | |
tree | bc8ca9254b66aa873a8497acf0e97a7dcd1c7658 /device/bluetooth | |
parent | 1dc1f38dbb4a6f9c39693c82fb00febb774fda25 (diff) | |
download | chromium_src-8696f577d5cb8198d7ffa5939d4fb537282ca7c2.zip chromium_src-8696f577d5cb8198d7ffa5939d4fb537282ca7c2.tar.gz chromium_src-8696f577d5cb8198d7ffa5939d4fb537282ca7c2.tar.bz2 |
Factor out a BluetoothChannelMac base class and a BluetoothRfcommChannelMac subclass.
These will allow the BluetoothSocketMac code to treat RFCOMM and L2CAP channels
uniformly, abstracting any differences via the BluetoothChannelMac class.
BUG=372495
TEST=BluetoothTest app
R=keybuk@chromium.org
Review URL: https://codereview.chromium.org/328903002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@276647 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'device/bluetooth')
-rw-r--r-- | device/bluetooth/bluetooth.gyp | 4 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_channel_mac.h | 59 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_channel_mac.mm | 22 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_rfcomm_channel_mac.h | 67 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_rfcomm_channel_mac.mm | 168 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_socket_mac.h | 35 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_socket_mac.mm | 200 |
7 files changed, 395 insertions, 160 deletions
diff --git a/device/bluetooth/bluetooth.gyp b/device/bluetooth/bluetooth.gyp index 648f4de..1f885a5 100644 --- a/device/bluetooth/bluetooth.gyp +++ b/device/bluetooth/bluetooth.gyp @@ -31,6 +31,8 @@ 'bluetooth_adapter_mac.mm', 'bluetooth_adapter_win.cc', 'bluetooth_adapter_win.h', + 'bluetooth_channel_mac.mm', + 'bluetooth_channel_mac.h', 'bluetooth_device.cc', 'bluetooth_device.h', 'bluetooth_device_chromeos.cc', @@ -57,6 +59,8 @@ 'bluetooth_remote_gatt_descriptor_chromeos.h', 'bluetooth_remote_gatt_service_chromeos.cc', 'bluetooth_remote_gatt_service_chromeos.h', + 'bluetooth_rfcomm_channel_mac.mm', + 'bluetooth_rfcomm_channel_mac.h', 'bluetooth_service_record.cc', 'bluetooth_service_record.h', 'bluetooth_service_record_win.cc', diff --git a/device/bluetooth/bluetooth_channel_mac.h b/device/bluetooth/bluetooth_channel_mac.h new file mode 100644 index 0000000..fa54d56 --- /dev/null +++ b/device/bluetooth/bluetooth_channel_mac.h @@ -0,0 +1,59 @@ +// Copyright 2014 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_CHANNEL_MAC_H_ +#define DEVICE_BLUETOOTH_BLUETOOTH_CHANNEL_MAC_H_ + +#import <IOKit/IOReturn.h> + +#include <string> + +#include "base/macros.h" + +namespace device { + +class BluetoothSocketMac; + +// Wraps a native RFCOMM or L2CAP channel. +class BluetoothChannelMac { + public: + BluetoothChannelMac(); + virtual ~BluetoothChannelMac(); + + // Sets the channel's owning socket to |socket|. Should only be called if the + // socket was previously unset. Note: This can synchronously call back into + // socket->OnChannelOpenComplete(). + virtual void SetSocket(BluetoothSocketMac* socket); + + // Returns the Bluetooth address for the device associated with |this| + // channel. + virtual std::string GetDeviceAddress() = 0; + + // Returns the outgoing MTU (maximum transmission unit) for the channel. + virtual uint16_t GetOutgoingMTU() = 0; + + // Writes |data| of length |length| bytes into the channel. The |refcon| is a + // user-supplied value that gets passed to the write callback. + // Returns kIOReturnSuccess if the data was buffered successfully. + // If the return value is an error condition none of the data was sent. + // The number of bytes to be sent must not exceed the channel MTU. + // + // Once the data has been successfully passed to the hardware to be + // transmitted, the socket's method OnChannelWriteComplete() will be called + // with the |refcon| that was passed to this method. + virtual IOReturn WriteAsync(void* data, uint16_t length, void* refcon) = 0; + + protected: + BluetoothSocketMac* socket() { return socket_; } + + private: + // The socket that owns |this|. + BluetoothSocketMac* socket_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothChannelMac); +}; + +} // namespace device + +#endif // DEVICE_BLUETOOTH_BLUETOOTH_CHANNEL_MAC_H_ diff --git a/device/bluetooth/bluetooth_channel_mac.mm b/device/bluetooth/bluetooth_channel_mac.mm new file mode 100644 index 0000000..63b8f68 --- /dev/null +++ b/device/bluetooth/bluetooth_channel_mac.mm @@ -0,0 +1,22 @@ +// Copyright 2014 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. + +#include "device/bluetooth/bluetooth_channel_mac.h" + +#include "base/logging.h" + +namespace device { + +BluetoothChannelMac::BluetoothChannelMac() : socket_(NULL) { +} + +BluetoothChannelMac::~BluetoothChannelMac() { +} + +void BluetoothChannelMac::SetSocket(BluetoothSocketMac* socket) { + DCHECK(!socket_); + socket_ = socket; +} + +} // namespace device diff --git a/device/bluetooth/bluetooth_rfcomm_channel_mac.h b/device/bluetooth/bluetooth_rfcomm_channel_mac.h new file mode 100644 index 0000000..d381496 --- /dev/null +++ b/device/bluetooth/bluetooth_rfcomm_channel_mac.h @@ -0,0 +1,67 @@ +// Copyright 2014 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_RFCOMM_CHANNEL_MAC_H_ +#define DEVICE_BLUETOOTH_BLUETOOTH_RFCOMM_CHANNEL_MAC_H_ + +#import <IOBluetooth/IOBluetooth.h> +#import <IOKit/IOReturn.h> + +#include "base/mac/scoped_nsobject.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "device/bluetooth/bluetooth_channel_mac.h" + +@class BluetoothRfcommChannelDelegate; + +namespace device { + +class BluetoothRfcommChannelMac : public BluetoothChannelMac { + public: + // Creates a new RFCOMM channel wrapper with the given |socket| and native + // |channel|. + // NOTE: The |channel| is expected to already be retained. + BluetoothRfcommChannelMac(BluetoothSocketMac* socket, + IOBluetoothRFCOMMChannel* channel); + virtual ~BluetoothRfcommChannelMac(); + + // Opens a new RFCOMM channel with Channel ID |channel_id| to the target + // |device|. Returns the opened channel and sets |status| to kIOReturnSuccess + // if the open process was successfully started (or if an existing RFCOMM + // channel was found). Otherwise, sets |status| to an error status. + static scoped_ptr<BluetoothRfcommChannelMac> OpenAsync( + BluetoothSocketMac* socket, + IOBluetoothDevice* device, + uint8 channel_id, + IOReturn* status); + + // BluetoothChannelMac: + virtual void SetSocket(BluetoothSocketMac* socket) OVERRIDE; + virtual std::string GetDeviceAddress() OVERRIDE; + virtual uint16_t GetOutgoingMTU() OVERRIDE; + virtual IOReturn WriteAsync(void* data, + uint16_t length, + void* refcon) OVERRIDE; + + void OnChannelOpenComplete(IOBluetoothRFCOMMChannel* channel, + IOReturn status); + void OnChannelClosed(IOBluetoothRFCOMMChannel* channel); + void OnChannelDataReceived(IOBluetoothRFCOMMChannel* channel, + void* data, + size_t length); + void OnChannelWriteComplete(IOBluetoothRFCOMMChannel* channel, + void* refcon, + IOReturn status); + + private: + // The wrapped native RFCOMM channel. + base::scoped_nsobject<IOBluetoothRFCOMMChannel> channel_; + base::scoped_nsobject<BluetoothRfcommChannelDelegate> delegate_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothRfcommChannelMac); +}; + +} // namespace device + +#endif // DEVICE_BLUETOOTH_BLUETOOTH_RFCOMM_CHANNEL_MAC_H_ diff --git a/device/bluetooth/bluetooth_rfcomm_channel_mac.mm b/device/bluetooth/bluetooth_rfcomm_channel_mac.mm new file mode 100644 index 0000000..8697ef6 --- /dev/null +++ b/device/bluetooth/bluetooth_rfcomm_channel_mac.mm @@ -0,0 +1,168 @@ +// Copyright 2014 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. + +#include "device/bluetooth/bluetooth_rfcomm_channel_mac.h" + +#include "base/logging.h" +#include "device/bluetooth/bluetooth_device_mac.h" +#include "device/bluetooth/bluetooth_socket_mac.h" + +// A simple delegate class for an open RFCOMM channel that forwards methods to +// its wrapped |channel_|. +@interface BluetoothRfcommChannelDelegate + : NSObject <IOBluetoothRFCOMMChannelDelegate> { + @private + device::BluetoothRfcommChannelMac* channel_; // weak +} + +- (id)initWithChannel:(device::BluetoothRfcommChannelMac*)channel; + +@end + +@implementation BluetoothRfcommChannelDelegate + +- (id)initWithChannel:(device::BluetoothRfcommChannelMac*)channel { + if ((self = [super init])) + channel_ = channel; + + return self; +} + +- (void)rfcommChannelOpenComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel + status:(IOReturn)error { + channel_->OnChannelOpenComplete(rfcommChannel, error); +} + +- (void)rfcommChannelWriteComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel + refcon:(void*)refcon + status:(IOReturn)error { + channel_->OnChannelWriteComplete(rfcommChannel, refcon, error); +} + +- (void)rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel + data:(void*)dataPointer + length:(size_t)dataLength { + channel_->OnChannelDataReceived(rfcommChannel, dataPointer, dataLength); +} + +- (void)rfcommChannelClosed:(IOBluetoothRFCOMMChannel*)rfcommChannel { + channel_->OnChannelClosed(rfcommChannel); +} + +@end + +namespace device { + +BluetoothRfcommChannelMac::BluetoothRfcommChannelMac( + BluetoothSocketMac* socket, + IOBluetoothRFCOMMChannel* channel) + : channel_(channel), + delegate_(nil) { + SetSocket(socket); +} + +BluetoothRfcommChannelMac::~BluetoothRfcommChannelMac() { + [channel_ setDelegate:nil]; + [channel_ closeChannel]; +} + +// static +scoped_ptr<BluetoothRfcommChannelMac> BluetoothRfcommChannelMac::OpenAsync( + BluetoothSocketMac* socket, + IOBluetoothDevice* device, + uint8 channel_id, + IOReturn* status) { + DCHECK(socket); + scoped_ptr<BluetoothRfcommChannelMac> channel( + new BluetoothRfcommChannelMac(socket, nil)); + + // Retain the delegate, because IOBluetoothDevice's + // |-openRFCOMMChannelAsync:withChannelID:delegate:| assumes that it can take + // ownership of the delegate without calling |-retain| on it... + DCHECK(channel->delegate_); + [channel->delegate_ retain]; + IOBluetoothRFCOMMChannel* rfcomm_channel; + *status = [device openRFCOMMChannelAsync:&rfcomm_channel + withChannelID:channel_id + delegate:channel->delegate_]; + if (*status == kIOReturnSuccess) { + // Note: No need to retain the |rfcomm_channel| -- the returned channel is + // already retained. + channel->channel_.reset(rfcomm_channel); + } else { + channel.reset(); + } + + return channel.Pass(); +} + +void BluetoothRfcommChannelMac::SetSocket(BluetoothSocketMac* socket) { + BluetoothChannelMac::SetSocket(socket); + if (!this->socket()) + return; + + // Now that the socket is set, it's safe to associate a delegate, which can + // call back to the socket. + DCHECK(!delegate_); + delegate_.reset( + [[BluetoothRfcommChannelDelegate alloc] initWithChannel:this]); + [channel_ setDelegate:delegate_]; +} + +std::string BluetoothRfcommChannelMac::GetDeviceAddress() { + return BluetoothDeviceMac::GetDeviceAddress([channel_ getDevice]); +} + +uint16_t BluetoothRfcommChannelMac::GetOutgoingMTU() { + return [channel_ getMTU]; +} + +IOReturn BluetoothRfcommChannelMac::WriteAsync(void* data, + uint16_t length, + void* refcon) { + DCHECK_LE(length, GetOutgoingMTU()); + return [channel_ writeAsync:data length:length refcon:refcon]; +} + +void BluetoothRfcommChannelMac::OnChannelOpenComplete( + IOBluetoothRFCOMMChannel* channel, + IOReturn status) { + if (channel_) { + DCHECK_EQ(channel_, channel); + } else { + // The (potentially) asynchronous connection occurred synchronously. + // Should only be reachable from OpenAsync(). + DCHECK_EQ(status, kIOReturnSuccess); + } + + socket()->OnChannelOpenComplete( + BluetoothDeviceMac::GetDeviceAddress([channel getDevice]), status); +} + +void BluetoothRfcommChannelMac::OnChannelClosed( + IOBluetoothRFCOMMChannel* channel) { + DCHECK_EQ(channel_, channel); + socket()->OnChannelClosed(); +} + +void BluetoothRfcommChannelMac::OnChannelDataReceived( + IOBluetoothRFCOMMChannel* channel, + void* data, + size_t length) { + DCHECK_EQ(channel_, channel); + socket()->OnChannelDataReceived(data, length); +} + +void BluetoothRfcommChannelMac::OnChannelWriteComplete( + IOBluetoothRFCOMMChannel* channel, + void* refcon, + IOReturn status) { + // Note: We use "CHECK" below to ensure we never run into unforeseen + // occurrences of asynchronous callbacks, which could lead to data + // corruption. + CHECK_EQ(channel_, channel); + socket()->OnChannelWriteComplete(refcon, status); +} + +} // namespace device diff --git a/device/bluetooth/bluetooth_socket_mac.h b/device/bluetooth/bluetooth_socket_mac.h index 803cd53..a74d020 100644 --- a/device/bluetooth/bluetooth_socket_mac.h +++ b/device/bluetooth/bluetooth_socket_mac.h @@ -19,7 +19,6 @@ #include "device/bluetooth/bluetooth_socket.h" #include "device/bluetooth/bluetooth_uuid.h" -@class BluetoothRfcommChannelDelegate; @class BluetoothRfcommConnectionListener; namespace net { @@ -30,6 +29,7 @@ class IOBufferWithSize; namespace device { class BluetoothAdapter; +class BluetoothChannelMac; // Implements the BluetoothSocket class for the Mac OS X platform. class BluetoothSocketMac : public BluetoothSocket { @@ -93,18 +93,15 @@ class BluetoothSocketMac : public BluetoothSocket { const ErrorCompletionCallback& error_callback); // Called by BluetoothRfcommConnectionListener. - void OnRfcommChannelOpened(IOBluetoothRFCOMMChannel* rfcomm_channel); - - // Called by BluetoothRfcommChannelDelegate. - void OnRfcommChannelOpenComplete(IOBluetoothRFCOMMChannel* rfcomm_channel, - IOReturn status); - void OnRfcommChannelClosed(IOBluetoothRFCOMMChannel* rfcomm_channel); - void OnRfcommChannelDataReceived(IOBluetoothRFCOMMChannel* rfcomm_channel, - void* data, - size_t length); - void OnRfcommChannelWriteComplete(IOBluetoothRFCOMMChannel* rfcomm_channel, - void* refcon, - IOReturn status); + 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 { @@ -166,16 +163,12 @@ class BluetoothSocketMac : public BluetoothSocket { base::scoped_nsobject<BluetoothRfcommConnectionListener> rfcomm_connection_listener_; - // A simple delegate that forwards RFCOMM channel methods to |this| socket. - base::scoped_nsobject<BluetoothRfcommChannelDelegate> - rfcomm_channel_delegate_; - // A handle to the service record registered in the system SDP server. // Used to eventually unregister the service. BluetoothSDPServiceRecordHandle service_record_handle_; - // The IOBluetooth RFCOMM channel used to issue commands. - base::scoped_nsobject<IOBluetoothRFCOMMChannel> rfcomm_channel_; + // The channel used to issue commands. + scoped_ptr<BluetoothChannelMac> channel_; // Connection callbacks -- when a pending async connection is active. scoped_ptr<ConnectCallbacks> connect_callbacks_; @@ -193,8 +186,8 @@ class BluetoothSocketMac : public BluetoothSocket { // request. scoped_ptr<AcceptRequest> accept_request_; - // Queue of incoming RFCOMM connections. - std::queue<base::scoped_nsobject<IOBluetoothRFCOMMChannel>> accept_queue_; + // Queue of incoming connections. + std::queue<linked_ptr<BluetoothChannelMac>> accept_queue_; DISALLOW_COPY_AND_ASSIGN(BluetoothSocketMac); }; diff --git a/device/bluetooth/bluetooth_socket_mac.mm b/device/bluetooth/bluetooth_socket_mac.mm index a693430..67fb949 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 |