summaryrefslogtreecommitdiffstats
path: root/device/bluetooth
diff options
context:
space:
mode:
authorisherman@chromium.org <isherman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-12 12:59:20 +0000
committerisherman@chromium.org <isherman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-12 12:59:20 +0000
commit8696f577d5cb8198d7ffa5939d4fb537282ca7c2 (patch)
treebc8ca9254b66aa873a8497acf0e97a7dcd1c7658 /device/bluetooth
parent1dc1f38dbb4a6f9c39693c82fb00febb774fda25 (diff)
downloadchromium_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.gyp4
-rw-r--r--device/bluetooth/bluetooth_channel_mac.h59
-rw-r--r--device/bluetooth/bluetooth_channel_mac.mm22
-rw-r--r--device/bluetooth/bluetooth_rfcomm_channel_mac.h67
-rw-r--r--device/bluetooth/bluetooth_rfcomm_channel_mac.mm168
-rw-r--r--device/bluetooth/bluetooth_socket_mac.h35
-rw-r--r--device/bluetooth/bluetooth_socket_mac.mm200
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, &registered_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