summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorisherman@chromium.org <isherman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-14 19:31:48 +0000
committerisherman@chromium.org <isherman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-14 19:31:48 +0000
commitedc0de329de9d0a1fe3d2a4c07db9eee17666150 (patch)
tree1b7ed2e27b24d65ef85c2f1671b259199b2532d1
parentda8bc29b7285278a09fce6796fd9ccd39ca6a92f (diff)
downloadchromium_src-edc0de329de9d0a1fe3d2a4c07db9eee17666150.zip
chromium_src-edc0de329de9d0a1fe3d2a4c07db9eee17666150.tar.gz
chromium_src-edc0de329de9d0a1fe3d2a4c07db9eee17666150.tar.bz2
Add support for client L2CAP sockets on Mac.
BUG=372495 TEST=BluetoothTest app R=keybuk@chromium.org TBR=tapted@chromium.org Review URL: https://codereview.chromium.org/326313002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@277247 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--apps/app_shim/chrome_main_app_mode_mac.mm2
-rw-r--r--base/mac/sdk_forward_declarations.h8
-rw-r--r--device/bluetooth/bluetooth.gyp6
-rw-r--r--device/bluetooth/bluetooth_l2cap_channel_mac.h69
-rw-r--r--device/bluetooth/bluetooth_l2cap_channel_mac.mm172
-rw-r--r--device/bluetooth/bluetooth_rfcomm_channel_mac.h4
-rw-r--r--device/bluetooth/bluetooth_rfcomm_channel_mac.mm2
-rw-r--r--device/bluetooth/bluetooth_socket_mac.mm45
8 files changed, 286 insertions, 22 deletions
diff --git a/apps/app_shim/chrome_main_app_mode_mac.mm b/apps/app_shim/chrome_main_app_mode_mac.mm
index 1092142..ee81b77 100644
--- a/apps/app_shim/chrome_main_app_mode_mac.mm
+++ b/apps/app_shim/chrome_main_app_mode_mac.mm
@@ -155,7 +155,7 @@ AppShimController::AppShimController()
AppShimController::~AppShimController() {
// Un-set the delegate since NSApplication does not retain it.
- [NSApp setDelegate:nil];
+ [[NSApplication sharedApplication] setDelegate:nil];
}
void AppShimController::OnPingChromeReply(bool success) {
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h
index 70df98e..e53fdbd 100644
--- a/base/mac/sdk_forward_declarations.h
+++ b/base/mac/sdk_forward_declarations.h
@@ -14,9 +14,7 @@
#import <AppKit/AppKit.h>
#import <CoreWLAN/CoreWLAN.h>
#import <ImageCaptureCore/ImageCaptureCore.h>
-#import <IOBluetooth/objc/IOBluetoothDevice.h>
-#import <IOBluetooth/objc/IOBluetoothDeviceInquiry.h>
-#import <IOBluetooth/objc/IOBluetoothHostController.h>
+#import <IOBluetooth/IOBluetooth.h>
#if !defined(MAC_OS_X_VERSION_10_7) || \
MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
@@ -169,6 +167,10 @@ enum CWChannelBand {
aborted:(BOOL)aborted;
@end
+@interface IOBluetoothL2CAPChannel (LionSDK)
+@property(readonly) BluetoothL2CAPMTU outgoingMTU;
+@end
+
@interface IOBluetoothDevice (LionSDK)
- (NSString*)addressString;
- (unsigned int)classOfDevice;
diff --git a/device/bluetooth/bluetooth.gyp b/device/bluetooth/bluetooth.gyp
index 350dfe0..efcbe59 100644
--- a/device/bluetooth/bluetooth.gyp
+++ b/device/bluetooth/bluetooth.gyp
@@ -41,6 +41,8 @@
'bluetooth_device_mac.mm',
'bluetooth_device_win.cc',
'bluetooth_device_win.h',
+ 'bluetooth_discovery_manager_mac.mm',
+ 'bluetooth_discovery_manager_mac.h',
'bluetooth_discovery_session.cc',
'bluetooth_discovery_session.h',
'bluetooth_gatt_characteristic.cc',
@@ -51,8 +53,8 @@
'bluetooth_gatt_service.h',
'bluetooth_init_win.cc',
'bluetooth_init_win.h',
- 'bluetooth_discovery_manager_mac.mm',
- 'bluetooth_discovery_manager_mac.h',
+ 'bluetooth_l2cap_channel_mac.mm',
+ 'bluetooth_l2cap_channel_mac.h',
'bluetooth_pairing_chromeos.cc',
'bluetooth_pairing_chromeos.h',
'bluetooth_remote_gatt_characteristic_chromeos.cc',
diff --git a/device/bluetooth/bluetooth_l2cap_channel_mac.h b/device/bluetooth/bluetooth_l2cap_channel_mac.h
new file mode 100644
index 0000000..1d489a0
--- /dev/null
+++ b/device/bluetooth/bluetooth_l2cap_channel_mac.h
@@ -0,0 +1,69 @@
+// 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_L2CAP_CHANNEL_MAC_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_L2CAP_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 BluetoothL2capChannelDelegate;
+
+namespace device {
+
+class BluetoothL2capChannelMac : public BluetoothChannelMac {
+ public:
+ // Creates a new L2CAP channel wrapper with the given |socket| and native
+ // |channel|.
+ // NOTE: The |channel| is expected to already be retained.
+ BluetoothL2capChannelMac(BluetoothSocketMac* socket,
+ IOBluetoothL2CAPChannel* channel);
+ virtual ~BluetoothL2capChannelMac();
+
+ // Opens a new L2CAP 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 L2CAP
+ // channel was found). Otherwise, sets |status| to an error status.
+ static scoped_ptr<BluetoothL2capChannelMac> OpenAsync(
+ BluetoothSocketMac* socket,
+ IOBluetoothDevice* device,
+ BluetoothL2CAPPSM psm,
+ 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(IOBluetoothL2CAPChannel* channel,
+ IOReturn status);
+ void OnChannelClosed(IOBluetoothL2CAPChannel* channel);
+ void OnChannelDataReceived(IOBluetoothL2CAPChannel* channel,
+ void* data,
+ size_t length);
+ void OnChannelWriteComplete(IOBluetoothL2CAPChannel* channel,
+ void* refcon,
+ IOReturn status);
+
+ private:
+ // The wrapped native L2CAP channel.
+ base::scoped_nsobject<IOBluetoothL2CAPChannel> channel_;
+
+ // The delegate for the native channel.
+ base::scoped_nsobject<BluetoothL2capChannelDelegate> delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothL2capChannelMac);
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_L2CAP_CHANNEL_MAC_H_
diff --git a/device/bluetooth/bluetooth_l2cap_channel_mac.mm b/device/bluetooth/bluetooth_l2cap_channel_mac.mm
new file mode 100644
index 0000000..ff137ba
--- /dev/null
+++ b/device/bluetooth/bluetooth_l2cap_channel_mac.mm
@@ -0,0 +1,172 @@
+// 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_l2cap_channel_mac.h"
+
+#include "base/logging.h"
+#include "base/mac/sdk_forward_declarations.h"
+#include "device/bluetooth/bluetooth_device_mac.h"
+#include "device/bluetooth/bluetooth_socket_mac.h"
+
+// A simple delegate class for an open L2CAP channel that forwards methods to
+// its wrapped |channel_|.
+@interface BluetoothL2capChannelDelegate
+ : NSObject <IOBluetoothL2CAPChannelDelegate> {
+ @private
+ device::BluetoothL2capChannelMac* channel_; // weak
+}
+
+- (id)initWithChannel:(device::BluetoothL2capChannelMac*)channel;
+
+@end
+
+@implementation BluetoothL2capChannelDelegate
+
+- (id)initWithChannel:(device::BluetoothL2capChannelMac*)channel {
+ if ((self = [super init]))
+ channel_ = channel;
+
+ return self;
+}
+
+- (void)l2capChannelOpenComplete:(IOBluetoothL2CAPChannel*)l2capChannel
+ status:(IOReturn)error {
+ channel_->OnChannelOpenComplete(l2capChannel, error);
+}
+
+- (void)l2capChannelWriteComplete:(IOBluetoothL2CAPChannel*)l2capChannel
+ refcon:(void*)refcon
+ status:(IOReturn)error {
+ channel_->OnChannelWriteComplete(l2capChannel, refcon, error);
+}
+
+- (void)l2capChannelData:(IOBluetoothL2CAPChannel*)l2capChannel
+ data:(void*)dataPointer
+ length:(size_t)dataLength {
+ channel_->OnChannelDataReceived(l2capChannel, dataPointer, dataLength);
+}
+
+- (void)l2capChannelClosed:(IOBluetoothL2CAPChannel*)l2capChannel {
+ channel_->OnChannelClosed(l2capChannel);
+}
+
+// These methods are marked as optional in the 10.8 SDK, but not in the 10.6
+// SDK. These empty implementations can be removed once we drop the 10.6 SDK.
+- (void)l2capChannelReconfigured:(IOBluetoothL2CAPChannel*)l2capChannel {
+}
+- (void)l2capChannelQueueSpaceAvailable:(IOBluetoothL2CAPChannel*)l2capChannel {
+}
+@end
+
+namespace device {
+
+BluetoothL2capChannelMac::BluetoothL2capChannelMac(
+ BluetoothSocketMac* socket,
+ IOBluetoothL2CAPChannel* channel)
+ : channel_(channel),
+ delegate_(nil) {
+ SetSocket(socket);
+}
+
+BluetoothL2capChannelMac::~BluetoothL2capChannelMac() {
+ [channel_ setDelegate:nil];
+ [channel_ closeChannel];
+}
+
+// static
+scoped_ptr<BluetoothL2capChannelMac> BluetoothL2capChannelMac::OpenAsync(
+ BluetoothSocketMac* socket,
+ IOBluetoothDevice* device,
+ BluetoothL2CAPPSM psm,
+ IOReturn* status) {
+ DCHECK(socket);
+ scoped_ptr<BluetoothL2capChannelMac> channel(
+ new BluetoothL2capChannelMac(socket, nil));
+
+ // Retain the delegate, because IOBluetoothDevice's
+ // |-openL2CAPChannelAsync:withPSM:delegate:| assumes that it can take
+ // ownership of the delegate without calling |-retain| on it...
+ DCHECK(channel->delegate_);
+ [channel->delegate_ retain];
+ IOBluetoothL2CAPChannel* l2cap_channel;
+ *status = [device openL2CAPChannelAsync:&l2cap_channel
+ withPSM:psm
+ delegate:channel->delegate_];
+ if (*status == kIOReturnSuccess)
+ channel->channel_.reset([l2cap_channel retain]);
+ else
+ channel.reset();
+
+ return channel.Pass();
+}
+
+void BluetoothL2capChannelMac::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(
+ [[BluetoothL2capChannelDelegate alloc] initWithChannel:this]);
+ [channel_ setDelegate:delegate_];
+}
+
+std::string BluetoothL2capChannelMac::GetDeviceAddress() {
+ return BluetoothDeviceMac::GetDeviceAddress([channel_ getDevice]);
+}
+
+uint16_t BluetoothL2capChannelMac::GetOutgoingMTU() {
+ return [channel_ outgoingMTU];
+}
+
+IOReturn BluetoothL2capChannelMac::WriteAsync(void* data,
+ uint16_t length,
+ void* refcon) {
+ DCHECK_LE(length, GetOutgoingMTU());
+ return [channel_ writeAsync:data length:length refcon:refcon];
+}
+
+void BluetoothL2capChannelMac::OnChannelOpenComplete(
+ IOBluetoothL2CAPChannel* 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 BluetoothL2capChannelMac::OnChannelClosed(
+ IOBluetoothL2CAPChannel* channel) {
+ DCHECK_EQ(channel_, channel);
+ socket()->OnChannelClosed();
+}
+
+void BluetoothL2capChannelMac::OnChannelDataReceived(
+ IOBluetoothL2CAPChannel* channel,
+ void* data,
+ size_t length) {
+ DCHECK_EQ(channel_, channel);
+ socket()->OnChannelDataReceived(data, length);
+}
+
+void BluetoothL2capChannelMac::OnChannelWriteComplete(
+ IOBluetoothL2CAPChannel* 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_rfcomm_channel_mac.h b/device/bluetooth/bluetooth_rfcomm_channel_mac.h
index d381496..572d915 100644
--- a/device/bluetooth/bluetooth_rfcomm_channel_mac.h
+++ b/device/bluetooth/bluetooth_rfcomm_channel_mac.h
@@ -33,7 +33,7 @@ class BluetoothRfcommChannelMac : public BluetoothChannelMac {
static scoped_ptr<BluetoothRfcommChannelMac> OpenAsync(
BluetoothSocketMac* socket,
IOBluetoothDevice* device,
- uint8 channel_id,
+ BluetoothRFCOMMChannelID channel_id,
IOReturn* status);
// BluetoothChannelMac:
@@ -57,6 +57,8 @@ class BluetoothRfcommChannelMac : public BluetoothChannelMac {
private:
// The wrapped native RFCOMM channel.
base::scoped_nsobject<IOBluetoothRFCOMMChannel> channel_;
+
+ // The delegate for the native channel.
base::scoped_nsobject<BluetoothRfcommChannelDelegate> delegate_;
DISALLOW_COPY_AND_ASSIGN(BluetoothRfcommChannelMac);
diff --git a/device/bluetooth/bluetooth_rfcomm_channel_mac.mm b/device/bluetooth/bluetooth_rfcomm_channel_mac.mm
index 8697ef6..655fe57 100644
--- a/device/bluetooth/bluetooth_rfcomm_channel_mac.mm
+++ b/device/bluetooth/bluetooth_rfcomm_channel_mac.mm
@@ -71,7 +71,7 @@ BluetoothRfcommChannelMac::~BluetoothRfcommChannelMac() {
scoped_ptr<BluetoothRfcommChannelMac> BluetoothRfcommChannelMac::OpenAsync(
BluetoothSocketMac* socket,
IOBluetoothDevice* device,
- uint8 channel_id,
+ BluetoothRFCOMMChannelID channel_id,
IOReturn* status) {
DCHECK(socket);
scoped_ptr<BluetoothRfcommChannelMac> channel(
diff --git a/device/bluetooth/bluetooth_socket_mac.mm b/device/bluetooth/bluetooth_socket_mac.mm
index 67fb949..4868134 100644
--- a/device/bluetooth/bluetooth_socket_mac.mm
+++ b/device/bluetooth/bluetooth_socket_mac.mm
@@ -24,6 +24,7 @@
#include "device/bluetooth/bluetooth_channel_mac.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_device_mac.h"
+#include "device/bluetooth/bluetooth_l2cap_channel_mac.h"
#include "device/bluetooth/bluetooth_rfcomm_channel_mac.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
@@ -317,7 +318,7 @@ void BluetoothSocketMac::ListenUsingRfcomm(
adapter_ = adapter;
uuid_ = uuid;
- DVLOG(1) << uuid_.canonical_value() << ": Registering service.";
+ DVLOG(1) << uuid_.canonical_value() << ": Registering RFCOMM service.";
BluetoothRFCOMMChannelID registered_channel_id;
service_record_handle_ =
RegisterRfcommService(uuid, channel_id, &registered_channel_id);
@@ -375,17 +376,29 @@ void BluetoothSocketMac::OnSDPQueryComplete(
return;
}
- uint8 rfcomm_channel_id;
+ // Since RFCOMM is built on top of L2CAP, a service record with both should
+ // always be treated as RFCOMM.
+ BluetoothRFCOMMChannelID rfcomm_channel_id = BluetoothAdapter::kChannelAuto;
+ BluetoothL2CAPPSM l2cap_psm = BluetoothAdapter::kPsmAuto;
status = [record getRFCOMMChannelID:&rfcomm_channel_id];
if (status != kIOReturnSuccess) {
- // TODO(isherman): Add support for L2CAP sockets as well.
- error_callback.Run(kL2capNotSupported);
- return;
+ status = [record getL2CAPPSM:&l2cap_psm];
+ if (status != kIOReturnSuccess) {
+ error_callback.Run(kProfileNotFound);
+ return;
+ }
}
- DVLOG(1) << BluetoothDeviceMac::GetDeviceAddress(device) << " "
- << uuid_.canonical_value() << ": Opening RFCOMM channel: "
- << rfcomm_channel_id;
+ if (rfcomm_channel_id != BluetoothAdapter::kChannelAuto) {
+ DVLOG(1) << BluetoothDeviceMac::GetDeviceAddress(device) << " "
+ << uuid_.canonical_value() << ": Opening RFCOMM channel: "
+ << rfcomm_channel_id;
+ } else {
+ DCHECK_NE(l2cap_psm, BluetoothAdapter::kPsmAuto);
+ DVLOG(1) << BluetoothDeviceMac::GetDeviceAddress(device) << " "
+ << uuid_.canonical_value() << ": Opening L2CAP channel: "
+ << l2cap_psm;
+ }
// 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
@@ -394,8 +407,14 @@ void BluetoothSocketMac::OnSDPQueryComplete(
connect_callbacks_->success_callback = success_callback;
connect_callbacks_->error_callback = error_callback;
- channel_ = BluetoothRfcommChannelMac::OpenAsync(
- this, device, rfcomm_channel_id, &status);
+ if (rfcomm_channel_id != BluetoothAdapter::kChannelAuto) {
+ channel_ = BluetoothRfcommChannelMac::OpenAsync(
+ this, device, rfcomm_channel_id, &status);
+ } else {
+ DCHECK_NE(l2cap_psm, BluetoothAdapter::kPsmAuto);
+ channel_ =
+ BluetoothL2capChannelMac::OpenAsync(this, device, l2cap_psm, &status);
+ }
if (status != kIOReturnSuccess) {
std::stringstream error;
error << "Failed to connect bluetooth socket ("
@@ -407,7 +426,7 @@ void BluetoothSocketMac::OnSDPQueryComplete(
DVLOG(2) << BluetoothDeviceMac::GetDeviceAddress(device) << " "
<< uuid_.canonical_value()
- << ": RFCOMM channel opening in background.";
+ << ": channel opening in background.";
}
void BluetoothSocketMac::OnChannelOpened(
@@ -506,9 +525,7 @@ void BluetoothSocketMac::Receive(
receive_callbacks_->error_callback = error_callback;
}
-void BluetoothSocketMac::OnChannelDataReceived(
- void* data,
- size_t length) {
+void BluetoothSocketMac::OnChannelDataReceived(void* data, size_t length) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!is_connecting());