1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "device/bluetooth/bluetooth_l2cap_channel_mac.h"
7 #include "base/logging.h"
8 #include "base/mac/sdk_forward_declarations.h"
9 #include "device/bluetooth/bluetooth_device_mac.h"
10 #include "device/bluetooth/bluetooth_socket_mac.h"
12 // A simple delegate class for an open L2CAP channel that forwards methods to
13 // its wrapped |channel_|.
14 @interface BluetoothL2capChannelDelegate
15 : NSObject <IOBluetoothL2CAPChannelDelegate> {
17 device::BluetoothL2capChannelMac* channel_; // weak
20 - (id)initWithChannel:(device::BluetoothL2capChannelMac*)channel;
24 @implementation BluetoothL2capChannelDelegate
26 - (id)initWithChannel:(device::BluetoothL2capChannelMac*)channel {
27 if ((self = [super init]))
33 - (void)l2capChannelOpenComplete:(IOBluetoothL2CAPChannel*)l2capChannel
34 status:(IOReturn)error {
35 channel_->OnChannelOpenComplete(l2capChannel, error);
38 - (void)l2capChannelWriteComplete:(IOBluetoothL2CAPChannel*)l2capChannel
40 status:(IOReturn)error {
41 channel_->OnChannelWriteComplete(l2capChannel, refcon, error);
44 - (void)l2capChannelData:(IOBluetoothL2CAPChannel*)l2capChannel
45 data:(void*)dataPointer
46 length:(size_t)dataLength {
47 channel_->OnChannelDataReceived(l2capChannel, dataPointer, dataLength);
50 - (void)l2capChannelClosed:(IOBluetoothL2CAPChannel*)l2capChannel {
51 channel_->OnChannelClosed(l2capChannel);
54 // These methods are marked as optional in the 10.8 SDK, but not in the 10.6
55 // SDK. These empty implementations can be removed once we drop the 10.6 SDK.
56 - (void)l2capChannelReconfigured:(IOBluetoothL2CAPChannel*)l2capChannel {
58 - (void)l2capChannelQueueSpaceAvailable:(IOBluetoothL2CAPChannel*)l2capChannel {
65 BluetoothL2capChannelMac::BluetoothL2capChannelMac(
66 BluetoothSocketMac* socket,
67 IOBluetoothL2CAPChannel* channel)
73 BluetoothL2capChannelMac::~BluetoothL2capChannelMac() {
74 [channel_ setDelegate:nil];
75 [channel_ closeChannel];
79 scoped_ptr<BluetoothL2capChannelMac> BluetoothL2capChannelMac::OpenAsync(
80 BluetoothSocketMac* socket,
81 IOBluetoothDevice* device,
82 BluetoothL2CAPPSM psm,
85 scoped_ptr<BluetoothL2capChannelMac> channel(
86 new BluetoothL2capChannelMac(socket, nil));
88 // Retain the delegate, because IOBluetoothDevice's
89 // |-openL2CAPChannelAsync:withPSM:delegate:| assumes that it can take
90 // ownership of the delegate without calling |-retain| on it...
91 DCHECK(channel->delegate_);
92 [channel->delegate_ retain];
93 IOBluetoothL2CAPChannel* l2cap_channel;
94 *status = [device openL2CAPChannelAsync:&l2cap_channel
96 delegate:channel->delegate_];
97 if (*status == kIOReturnSuccess)
98 channel->channel_.reset([l2cap_channel retain]);
102 return channel.Pass();
105 void BluetoothL2capChannelMac::SetSocket(BluetoothSocketMac* socket) {
106 BluetoothChannelMac::SetSocket(socket);
110 // Now that the socket is set, it's safe to associate a delegate, which can
111 // call back to the socket.
114 [[BluetoothL2capChannelDelegate alloc] initWithChannel:this]);
115 [channel_ setDelegate:delegate_];
118 IOBluetoothDevice* BluetoothL2capChannelMac::GetDevice() {
119 return [channel_ getDevice];
122 uint16_t BluetoothL2capChannelMac::GetOutgoingMTU() {
123 return [channel_ outgoingMTU];
126 IOReturn BluetoothL2capChannelMac::WriteAsync(void* data,
129 DCHECK_LE(length, GetOutgoingMTU());
130 return [channel_ writeAsync:data length:length refcon:refcon];
133 void BluetoothL2capChannelMac::OnChannelOpenComplete(
134 IOBluetoothL2CAPChannel* channel,
137 DCHECK_EQ(channel_, channel);
139 // The (potentially) asynchronous connection occurred synchronously.
140 // Should only be reachable from OpenAsync().
141 DCHECK_EQ(status, kIOReturnSuccess);
144 socket()->OnChannelOpenComplete(
145 BluetoothDeviceMac::GetDeviceAddress([channel getDevice]), status);
148 void BluetoothL2capChannelMac::OnChannelClosed(
149 IOBluetoothL2CAPChannel* channel) {
150 DCHECK_EQ(channel_, channel);
151 socket()->OnChannelClosed();
154 void BluetoothL2capChannelMac::OnChannelDataReceived(
155 IOBluetoothL2CAPChannel* channel,
158 DCHECK_EQ(channel_, channel);
159 socket()->OnChannelDataReceived(data, length);
162 void BluetoothL2capChannelMac::OnChannelWriteComplete(
163 IOBluetoothL2CAPChannel* channel,
166 // Note: We use "CHECK" below to ensure we never run into unforeseen
167 // occurrences of asynchronous callbacks, which could lead to data
169 CHECK_EQ(channel_, channel);
170 socket()->OnChannelWriteComplete(refcon, status);
173 } // namespace device