Home | History | Annotate | Download | only in bluetooth
      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