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. 4 5 #include "device/bluetooth/bluetooth_rfcomm_channel_mac.h" 6 7 #include "base/logging.h" 8 #include "device/bluetooth/bluetooth_device_mac.h" 9 #include "device/bluetooth/bluetooth_socket_mac.h" 10 11 // A simple delegate class for an open RFCOMM channel that forwards methods to 12 // its wrapped |channel_|. 13 @interface BluetoothRfcommChannelDelegate 14 : NSObject <IOBluetoothRFCOMMChannelDelegate> { 15 @private 16 device::BluetoothRfcommChannelMac* channel_; // weak 17 } 18 19 - (id)initWithChannel:(device::BluetoothRfcommChannelMac*)channel; 20 21 @end 22 23 @implementation BluetoothRfcommChannelDelegate 24 25 - (id)initWithChannel:(device::BluetoothRfcommChannelMac*)channel { 26 if ((self = [super init])) 27 channel_ = channel; 28 29 return self; 30 } 31 32 - (void)rfcommChannelOpenComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel 33 status:(IOReturn)error { 34 channel_->OnChannelOpenComplete(rfcommChannel, error); 35 } 36 37 - (void)rfcommChannelWriteComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel 38 refcon:(void*)refcon 39 status:(IOReturn)error { 40 channel_->OnChannelWriteComplete(rfcommChannel, refcon, error); 41 } 42 43 - (void)rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel 44 data:(void*)dataPointer 45 length:(size_t)dataLength { 46 channel_->OnChannelDataReceived(rfcommChannel, dataPointer, dataLength); 47 } 48 49 - (void)rfcommChannelClosed:(IOBluetoothRFCOMMChannel*)rfcommChannel { 50 channel_->OnChannelClosed(rfcommChannel); 51 } 52 53 @end 54 55 namespace device { 56 57 BluetoothRfcommChannelMac::BluetoothRfcommChannelMac( 58 BluetoothSocketMac* socket, 59 IOBluetoothRFCOMMChannel* channel) 60 : channel_(channel), 61 delegate_(nil) { 62 SetSocket(socket); 63 } 64 65 BluetoothRfcommChannelMac::~BluetoothRfcommChannelMac() { 66 [channel_ setDelegate:nil]; 67 [channel_ closeChannel]; 68 } 69 70 // static 71 scoped_ptr<BluetoothRfcommChannelMac> BluetoothRfcommChannelMac::OpenAsync( 72 BluetoothSocketMac* socket, 73 IOBluetoothDevice* device, 74 BluetoothRFCOMMChannelID channel_id, 75 IOReturn* status) { 76 DCHECK(socket); 77 scoped_ptr<BluetoothRfcommChannelMac> channel( 78 new BluetoothRfcommChannelMac(socket, nil)); 79 80 // Retain the delegate, because IOBluetoothDevice's 81 // |-openRFCOMMChannelAsync:withChannelID:delegate:| assumes that it can take 82 // ownership of the delegate without calling |-retain| on it... 83 DCHECK(channel->delegate_); 84 [channel->delegate_ retain]; 85 IOBluetoothRFCOMMChannel* rfcomm_channel; 86 *status = [device openRFCOMMChannelAsync:&rfcomm_channel 87 withChannelID:channel_id 88 delegate:channel->delegate_]; 89 if (*status == kIOReturnSuccess) { 90 // Note: No need to retain the |rfcomm_channel| -- the returned channel is 91 // already retained. 92 channel->channel_.reset(rfcomm_channel); 93 } else { 94 channel.reset(); 95 } 96 97 return channel.Pass(); 98 } 99 100 void BluetoothRfcommChannelMac::SetSocket(BluetoothSocketMac* socket) { 101 BluetoothChannelMac::SetSocket(socket); 102 if (!this->socket()) 103 return; 104 105 // Now that the socket is set, it's safe to associate a delegate, which can 106 // call back to the socket. 107 DCHECK(!delegate_); 108 delegate_.reset( 109 [[BluetoothRfcommChannelDelegate alloc] initWithChannel:this]); 110 [channel_ setDelegate:delegate_]; 111 } 112 113 IOBluetoothDevice* BluetoothRfcommChannelMac::GetDevice() { 114 return [channel_ getDevice]; 115 } 116 117 uint16_t BluetoothRfcommChannelMac::GetOutgoingMTU() { 118 return [channel_ getMTU]; 119 } 120 121 IOReturn BluetoothRfcommChannelMac::WriteAsync(void* data, 122 uint16_t length, 123 void* refcon) { 124 DCHECK_LE(length, GetOutgoingMTU()); 125 return [channel_ writeAsync:data length:length refcon:refcon]; 126 } 127 128 void BluetoothRfcommChannelMac::OnChannelOpenComplete( 129 IOBluetoothRFCOMMChannel* channel, 130 IOReturn status) { 131 if (channel_) { 132 DCHECK_EQ(channel_, channel); 133 } else { 134 // The (potentially) asynchronous connection occurred synchronously. 135 // Should only be reachable from OpenAsync(). 136 DCHECK_EQ(status, kIOReturnSuccess); 137 } 138 139 socket()->OnChannelOpenComplete( 140 BluetoothDeviceMac::GetDeviceAddress([channel getDevice]), status); 141 } 142 143 void BluetoothRfcommChannelMac::OnChannelClosed( 144 IOBluetoothRFCOMMChannel* channel) { 145 DCHECK_EQ(channel_, channel); 146 socket()->OnChannelClosed(); 147 } 148 149 void BluetoothRfcommChannelMac::OnChannelDataReceived( 150 IOBluetoothRFCOMMChannel* channel, 151 void* data, 152 size_t length) { 153 DCHECK_EQ(channel_, channel); 154 socket()->OnChannelDataReceived(data, length); 155 } 156 157 void BluetoothRfcommChannelMac::OnChannelWriteComplete( 158 IOBluetoothRFCOMMChannel* channel, 159 void* refcon, 160 IOReturn status) { 161 // Note: We use "CHECK" below to ensure we never run into unforeseen 162 // occurrences of asynchronous callbacks, which could lead to data 163 // corruption. 164 CHECK_EQ(channel_, channel); 165 socket()->OnChannelWriteComplete(refcon, status); 166 } 167 168 } // namespace device 169