bluetooth_l2cap_channel_mac.mm 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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. #include "device/bluetooth/bluetooth_l2cap_channel_mac.h"
  5. #include <memory>
  6. #include "base/check_op.h"
  7. #include "base/memory/raw_ptr.h"
  8. #include "device/bluetooth/bluetooth_classic_device_mac.h"
  9. #include "device/bluetooth/bluetooth_socket_mac.h"
  10. // A simple delegate class for an open L2CAP channel that forwards methods to
  11. // its wrapped |channel_|.
  12. @interface BluetoothL2capChannelDelegate
  13. : NSObject <IOBluetoothL2CAPChannelDelegate> {
  14. @private
  15. raw_ptr<device::BluetoothL2capChannelMac> _channel; // weak
  16. }
  17. - (instancetype)initWithChannel:(device::BluetoothL2capChannelMac*)channel;
  18. @end
  19. @implementation BluetoothL2capChannelDelegate
  20. - (instancetype)initWithChannel:(device::BluetoothL2capChannelMac*)channel {
  21. if ((self = [super init]))
  22. _channel = channel;
  23. return self;
  24. }
  25. - (void)l2capChannelOpenComplete:(IOBluetoothL2CAPChannel*)l2capChannel
  26. status:(IOReturn)error {
  27. _channel->OnChannelOpenComplete(l2capChannel, error);
  28. }
  29. - (void)l2capChannelWriteComplete:(IOBluetoothL2CAPChannel*)l2capChannel
  30. refcon:(void*)refcon
  31. status:(IOReturn)error {
  32. _channel->OnChannelWriteComplete(l2capChannel, refcon, error);
  33. }
  34. - (void)l2capChannelData:(IOBluetoothL2CAPChannel*)l2capChannel
  35. data:(void*)dataPointer
  36. length:(size_t)dataLength {
  37. _channel->OnChannelDataReceived(l2capChannel, dataPointer, dataLength);
  38. }
  39. - (void)l2capChannelClosed:(IOBluetoothL2CAPChannel*)l2capChannel {
  40. _channel->OnChannelClosed(l2capChannel);
  41. }
  42. @end
  43. namespace device {
  44. BluetoothL2capChannelMac::BluetoothL2capChannelMac(
  45. BluetoothSocketMac* socket,
  46. IOBluetoothL2CAPChannel* channel)
  47. : channel_(channel),
  48. delegate_(nil) {
  49. SetSocket(socket);
  50. }
  51. BluetoothL2capChannelMac::~BluetoothL2capChannelMac() {
  52. [channel_ setDelegate:nil];
  53. [channel_ closeChannel];
  54. }
  55. // static
  56. std::unique_ptr<BluetoothL2capChannelMac> BluetoothL2capChannelMac::OpenAsync(
  57. BluetoothSocketMac* socket,
  58. IOBluetoothDevice* device,
  59. BluetoothL2CAPPSM psm,
  60. IOReturn* status) {
  61. DCHECK(socket);
  62. std::unique_ptr<BluetoothL2capChannelMac> channel(
  63. new BluetoothL2capChannelMac(socket, nil));
  64. // Retain the delegate, because IOBluetoothDevice's
  65. // |-openL2CAPChannelAsync:withPSM:delegate:| assumes that it can take
  66. // ownership of the delegate without calling |-retain| on it...
  67. DCHECK(channel->delegate_);
  68. [channel->delegate_ retain];
  69. IOBluetoothL2CAPChannel* l2cap_channel;
  70. *status = [device openL2CAPChannelAsync:&l2cap_channel
  71. withPSM:psm
  72. delegate:channel->delegate_];
  73. if (*status == kIOReturnSuccess)
  74. channel->channel_.reset([l2cap_channel retain]);
  75. else
  76. channel.reset();
  77. return channel;
  78. }
  79. void BluetoothL2capChannelMac::SetSocket(BluetoothSocketMac* socket) {
  80. BluetoothChannelMac::SetSocket(socket);
  81. if (!this->socket())
  82. return;
  83. // Now that the socket is set, it's safe to associate a delegate, which can
  84. // call back to the socket.
  85. DCHECK(!delegate_);
  86. delegate_.reset(
  87. [[BluetoothL2capChannelDelegate alloc] initWithChannel:this]);
  88. [channel_ setDelegate:delegate_];
  89. }
  90. IOBluetoothDevice* BluetoothL2capChannelMac::GetDevice() {
  91. return [channel_ device];
  92. }
  93. uint16_t BluetoothL2capChannelMac::GetOutgoingMTU() {
  94. return [channel_ outgoingMTU];
  95. }
  96. IOReturn BluetoothL2capChannelMac::WriteAsync(void* data,
  97. uint16_t length,
  98. void* refcon) {
  99. DCHECK_LE(length, GetOutgoingMTU());
  100. return [channel_ writeAsync:data length:length refcon:refcon];
  101. }
  102. void BluetoothL2capChannelMac::OnChannelOpenComplete(
  103. IOBluetoothL2CAPChannel* channel,
  104. IOReturn status) {
  105. if (channel_) {
  106. DCHECK_EQ(channel_, channel);
  107. } else {
  108. // The (potentially) asynchronous connection occurred synchronously.
  109. // Should only be reachable from OpenAsync().
  110. DCHECK_EQ(status, kIOReturnSuccess);
  111. }
  112. socket()->OnChannelOpenComplete(
  113. BluetoothClassicDeviceMac::GetDeviceAddress([channel device]), status);
  114. }
  115. void BluetoothL2capChannelMac::OnChannelClosed(
  116. IOBluetoothL2CAPChannel* channel) {
  117. DCHECK_EQ(channel_, channel);
  118. socket()->OnChannelClosed();
  119. }
  120. void BluetoothL2capChannelMac::OnChannelDataReceived(
  121. IOBluetoothL2CAPChannel* channel,
  122. void* data,
  123. size_t length) {
  124. DCHECK_EQ(channel_, channel);
  125. socket()->OnChannelDataReceived(data, length);
  126. }
  127. void BluetoothL2capChannelMac::OnChannelWriteComplete(
  128. IOBluetoothL2CAPChannel* channel,
  129. void* refcon,
  130. IOReturn status) {
  131. // Note: We use "CHECK" below to ensure we never run into unforeseen
  132. // occurrences of asynchronous callbacks, which could lead to data
  133. // corruption.
  134. CHECK_EQ(channel_, channel);
  135. socket()->OnChannelWriteComplete(refcon, status);
  136. }
  137. } // namespace device