| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "device/bluetooth/bluetooth_socket_mac.h" | 5 #include "device/bluetooth/bluetooth_socket_mac.h" |
| 6 | 6 |
| 7 #import <IOBluetooth/objc/IOBluetoothDevice.h> | 7 #import <IOBluetooth/IOBluetooth.h> |
| 8 #import <IOBluetooth/objc/IOBluetoothRFCOMMChannel.h> | |
| 9 #import <IOBluetooth/objc/IOBluetoothSDPServiceRecord.h> | |
| 10 | 8 |
| 11 #include <limits> | 9 #include <limits> |
| 12 #include <sstream> | 10 #include <sstream> |
| 13 #include <string> | 11 #include <string> |
| 14 | 12 |
| 15 #include "base/basictypes.h" | 13 #include "base/basictypes.h" |
| 14 #include "base/bind.h" |
| 16 #include "base/callback_helpers.h" | 15 #include "base/callback_helpers.h" |
| 17 #include "base/memory/ref_counted.h" | 16 #include "base/memory/ref_counted.h" |
| 18 #include "base/numerics/safe_conversions.h" | 17 #include "base/numerics/safe_conversions.h" |
| 19 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
| 20 #include "base/strings/sys_string_conversions.h" | 19 #include "base/strings/sys_string_conversions.h" |
| 21 #include "base/threading/thread_restrictions.h" | 20 #include "base/threading/thread_restrictions.h" |
| 22 #include "device/bluetooth/bluetooth_service_record.h" | 21 #include "device/bluetooth/bluetooth_service_record.h" |
| 23 #include "device/bluetooth/bluetooth_service_record_mac.h" | 22 #include "device/bluetooth/bluetooth_service_record_mac.h" |
| 24 #include "net/base/io_buffer.h" | 23 #include "net/base/io_buffer.h" |
| 25 | 24 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 | 99 |
| 101 BluetoothSocketMac::ReceiveCallbacks::ReceiveCallbacks() {} | 100 BluetoothSocketMac::ReceiveCallbacks::ReceiveCallbacks() {} |
| 102 | 101 |
| 103 BluetoothSocketMac::ReceiveCallbacks::~ReceiveCallbacks() {} | 102 BluetoothSocketMac::ReceiveCallbacks::~ReceiveCallbacks() {} |
| 104 | 103 |
| 105 BluetoothSocketMac::ConnectCallbacks::ConnectCallbacks() {} | 104 BluetoothSocketMac::ConnectCallbacks::ConnectCallbacks() {} |
| 106 | 105 |
| 107 BluetoothSocketMac::ConnectCallbacks::~ConnectCallbacks() {} | 106 BluetoothSocketMac::ConnectCallbacks::~ConnectCallbacks() {} |
| 108 | 107 |
| 109 // static | 108 // static |
| 110 scoped_refptr<BluetoothSocketMac> BluetoothSocketMac::CreateBluetoothSocket( | 109 void BluetoothSocketMac::Connect( |
| 111 IOBluetoothSDPServiceRecord* record) { | 110 IOBluetoothSDPServiceRecord* record, |
| 112 return new BluetoothSocketMac(record); | 111 const ConnectSuccessCallback& success_callback, |
| 112 const ErrorCompletionCallback& error_callback) { |
| 113 scoped_refptr<BluetoothSocketMac> socket(new BluetoothSocketMac()); |
| 114 socket->ConnectImpl(record, success_callback, error_callback); |
| 113 } | 115 } |
| 114 | 116 |
| 115 BluetoothSocketMac::BluetoothSocketMac( | 117 // static |
| 116 IOBluetoothSDPServiceRecord* record) | 118 void BluetoothSocketMac::AcceptConnection( |
| 117 : record_([record retain]), | 119 IOBluetoothRFCOMMChannel* rfcomm_channel, |
| 118 delegate_([[BluetoothRFCOMMChannelDelegate alloc] initWithSocket:this]) { | 120 const ConnectSuccessCallback& success_callback, |
| 119 DCHECK(thread_checker_.CalledOnValidThread()); | 121 const ErrorCompletionCallback& error_callback) { |
| 122 scoped_refptr<BluetoothSocketMac> socket(new BluetoothSocketMac()); |
| 123 socket->AcceptConnectionImpl( |
| 124 rfcomm_channel, success_callback, error_callback); |
| 125 } |
| 126 |
| 127 BluetoothSocketMac::BluetoothSocketMac() |
| 128 : delegate_([[BluetoothRFCOMMChannelDelegate alloc] initWithSocket:this]) { |
| 120 } | 129 } |
| 121 | 130 |
| 122 BluetoothSocketMac::~BluetoothSocketMac() { | 131 BluetoothSocketMac::~BluetoothSocketMac() { |
| 123 DCHECK(thread_checker_.CalledOnValidThread()); | 132 DCHECK(thread_checker_.CalledOnValidThread()); |
| 124 ReleaseChannel(); | 133 ReleaseChannel(); |
| 125 } | 134 } |
| 126 | 135 |
| 127 void BluetoothSocketMac::ReleaseChannel() { | 136 void BluetoothSocketMac::ReleaseChannel() { |
| 128 DCHECK(thread_checker_.CalledOnValidThread()); | 137 DCHECK(thread_checker_.CalledOnValidThread()); |
| 129 if (rfcomm_channel_) { | 138 if (rfcomm_channel_) { |
| 130 [rfcomm_channel_ setDelegate:nil]; | 139 [rfcomm_channel_ setDelegate:nil]; |
| 131 [rfcomm_channel_ closeChannel]; | 140 [rfcomm_channel_ closeChannel]; |
| 132 rfcomm_channel_.reset(); | 141 rfcomm_channel_.reset(); |
| 133 } | 142 } |
| 134 | 143 |
| 135 // Closing the channel above prevents the callback delegate from being called | 144 // Closing the channel above prevents the callback delegate from being called |
| 136 // so it is now safe to release all callback state. | 145 // so it is now safe to release all callback state. |
| 137 connect_callbacks_.reset(); | 146 connect_callbacks_.reset(); |
| 138 receive_callbacks_.reset(); | 147 receive_callbacks_.reset(); |
| 139 empty_queue(receive_queue_); | 148 empty_queue(receive_queue_); |
| 140 empty_queue(send_queue_); | 149 empty_queue(send_queue_); |
| 141 } | 150 } |
| 142 | 151 |
| 143 void BluetoothSocketMac::Connect( | 152 void BluetoothSocketMac::ConnectImpl( |
| 144 const base::Closure& success_callback, | 153 IOBluetoothSDPServiceRecord* record, |
| 154 const ConnectSuccessCallback& success_callback, |
| 145 const ErrorCompletionCallback& error_callback) { | 155 const ErrorCompletionCallback& error_callback) { |
| 146 DCHECK(thread_checker_.CalledOnValidThread()); | 156 DCHECK(thread_checker_.CalledOnValidThread()); |
| 147 | 157 |
| 148 if (connecting()) { | 158 if (connecting()) { |
| 149 error_callback.Run(kSocketConnecting); | 159 error_callback.Run(kSocketConnecting); |
| 150 return; | 160 return; |
| 151 } | 161 } |
| 152 | 162 |
| 153 if (rfcomm_channel_) { | 163 if (rfcomm_channel_) { |
| 154 error_callback.Run(kSocketAlreadyConnected); | 164 error_callback.Run(kSocketAlreadyConnected); |
| 155 return; | 165 return; |
| 156 } | 166 } |
| 157 | 167 |
| 158 uint8 rfcomm_channel_id; | 168 uint8 rfcomm_channel_id; |
| 159 IOReturn status = [record_ getRFCOMMChannelID:&rfcomm_channel_id]; | 169 IOReturn status = [record getRFCOMMChannelID:&rfcomm_channel_id]; |
| 160 if (status != kIOReturnSuccess) { | 170 if (status != kIOReturnSuccess) { |
| 161 // TODO(youngki) add support for L2CAP sockets as well. | 171 // TODO(youngki) add support for L2CAP sockets as well. |
| 162 error_callback.Run(kL2CAPNotSupported); | 172 error_callback.Run(kL2CAPNotSupported); |
| 163 return; | 173 return; |
| 164 } | 174 } |
| 165 | 175 |
| 166 IOBluetoothDevice* device = [record_ device]; | 176 IOBluetoothDevice* device = [record device]; |
| 167 IOBluetoothRFCOMMChannel* rfcomm_channel; | 177 IOBluetoothRFCOMMChannel* rfcomm_channel; |
| 168 status = [device openRFCOMMChannelAsync:&rfcomm_channel | 178 status = [device openRFCOMMChannelAsync:&rfcomm_channel |
| 169 withChannelID:rfcomm_channel_id | 179 withChannelID:rfcomm_channel_id |
| 170 delegate:delegate_]; | 180 delegate:delegate_]; |
| 171 if (status != kIOReturnSuccess) { | 181 if (status != kIOReturnSuccess) { |
| 172 std::stringstream error; | 182 std::stringstream error; |
| 173 error << "Failed to connect bluetooth socket (" | 183 error << "Failed to connect bluetooth socket (" |
| 174 << base::SysNSStringToUTF8([device addressString]) << "): (" << status | 184 << base::SysNSStringToUTF8([device addressString]) << "): (" << status |
| 175 << ")"; | 185 << ")"; |
| 176 error_callback.Run(error.str()); | 186 error_callback.Run(error.str()); |
| 177 return; | 187 return; |
| 178 } | 188 } |
| 179 | 189 |
| 190 AcceptConnectionImpl(rfcomm_channel, success_callback, error_callback); |
| 191 } |
| 192 |
| 193 void BluetoothSocketMac::AcceptConnectionImpl( |
| 194 IOBluetoothRFCOMMChannel* rfcomm_channel, |
| 195 const ConnectSuccessCallback& success_callback, |
| 196 const ErrorCompletionCallback& error_callback) { |
| 180 connect_callbacks_.reset(new ConnectCallbacks()); | 197 connect_callbacks_.reset(new ConnectCallbacks()); |
| 181 connect_callbacks_->success_callback = success_callback; | 198 connect_callbacks_->success_callback = |
| 199 base::Bind(success_callback, scoped_refptr<BluetoothSocketMac>(this)); |
| 182 connect_callbacks_->error_callback = error_callback; | 200 connect_callbacks_->error_callback = error_callback; |
| 183 rfcomm_channel_.reset(rfcomm_channel); | 201 |
| 202 // Note: It's important to set the connect callbacks *prior* to setting the |
| 203 // delegate, as setting the delegate can synchronously call into |
| 204 // OnChannelOpened(). |
| 205 rfcomm_channel_.reset([rfcomm_channel retain]); |
| 184 [rfcomm_channel_ setDelegate:delegate_]; | 206 [rfcomm_channel_ setDelegate:delegate_]; |
| 185 } | 207 } |
| 186 | 208 |
| 187 void BluetoothSocketMac::OnChannelOpened( | 209 void BluetoothSocketMac::OnChannelOpened( |
| 188 IOBluetoothRFCOMMChannel* rfcomm_channel, | 210 IOBluetoothRFCOMMChannel* rfcomm_channel, |
| 189 IOReturn status) { | 211 IOReturn status) { |
| 190 DCHECK(thread_checker_.CalledOnValidThread()); | 212 DCHECK(thread_checker_.CalledOnValidThread()); |
| 191 DCHECK_EQ(rfcomm_channel_, rfcomm_channel); | 213 DCHECK_EQ(rfcomm_channel_, rfcomm_channel); |
| 192 DCHECK(connecting()); | 214 DCHECK(connecting()); |
| 193 | 215 |
| 194 scoped_ptr<ConnectCallbacks> temp = connect_callbacks_.Pass(); | 216 scoped_ptr<ConnectCallbacks> temp = connect_callbacks_.Pass(); |
| 195 if (status != kIOReturnSuccess) { | 217 if (status != kIOReturnSuccess) { |
| 196 ReleaseChannel(); | 218 ReleaseChannel(); |
| 197 std::stringstream error; | 219 std::stringstream error; |
| 198 error << "Failed to connect bluetooth socket (" | 220 error << "Failed to connect bluetooth socket (" |
| 199 << base::SysNSStringToUTF8([[record_ device] addressString]) << "): (" | 221 << base::SysNSStringToUTF8( |
| 222 [[rfcomm_channel_ getDevice] addressString]) << "): (" |
| 200 << status << ")"; | 223 << status << ")"; |
| 201 temp->error_callback.Run(error.str()); | 224 temp->error_callback.Run(error.str()); |
| 202 return; | 225 return; |
| 203 } | 226 } |
| 204 | 227 |
| 205 temp->success_callback.Run(); | 228 temp->success_callback.Run(); |
| 206 } | 229 } |
| 207 | 230 |
| 208 void BluetoothSocketMac::Close() { | 231 void BluetoothSocketMac::Close() { |
| 209 DCHECK(thread_checker_.CalledOnValidThread()); | 232 DCHECK(thread_checker_.CalledOnValidThread()); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 while (send_buffer->BytesRemaining() > 0) { | 332 while (send_buffer->BytesRemaining() > 0) { |
| 310 int byte_count = send_buffer->BytesRemaining(); | 333 int byte_count = send_buffer->BytesRemaining(); |
| 311 if (byte_count > mtu) | 334 if (byte_count > mtu) |
| 312 byte_count = mtu; | 335 byte_count = mtu; |
| 313 IOReturn status = [rfcomm_channel_ writeAsync:send_buffer->data() | 336 IOReturn status = [rfcomm_channel_ writeAsync:send_buffer->data() |
| 314 length:byte_count | 337 length:byte_count |
| 315 refcon:request.get()]; | 338 refcon:request.get()]; |
| 316 if (status != kIOReturnSuccess) { | 339 if (status != kIOReturnSuccess) { |
| 317 std::stringstream error; | 340 std::stringstream error; |
| 318 error << "Failed to connect bluetooth socket (" | 341 error << "Failed to connect bluetooth socket (" |
| 319 << base::SysNSStringToUTF8([[record_ device] addressString]) | 342 << base::SysNSStringToUTF8( |
| 343 [[rfcomm_channel_ getDevice] addressString]) |
| 320 << "): (" << status << ")"; | 344 << "): (" << status << ")"; |
| 321 // Remember the first error only | 345 // Remember the first error only |
| 322 if (request->status == kIOReturnSuccess) | 346 if (request->status == kIOReturnSuccess) |
| 323 request->status = status; | 347 request->status = status; |
| 324 request->error_signaled = true; | 348 request->error_signaled = true; |
| 325 request->error_callback.Run(error.str()); | 349 request->error_callback.Run(error.str()); |
| 326 // We may have failed to issue any write operation. In that case, there | 350 // We may have failed to issue any write operation. In that case, there |
| 327 // will be no corresponding completion callback for this particular | 351 // will be no corresponding completion callback for this particular |
| 328 // request, so we must forget about it now. | 352 // request, so we must forget about it now. |
| 329 if (request->active_async_writes == 0) { | 353 if (request->active_async_writes == 0) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 if (request->active_async_writes > 0) | 388 if (request->active_async_writes > 0) |
| 365 return; | 389 return; |
| 366 | 390 |
| 367 // If this was the last active async write for this request, remove it from | 391 // If this was the last active async write for this request, remove it from |
| 368 // the queue and call the appropriate callback associated to the request. | 392 // the queue and call the appropriate callback associated to the request. |
| 369 send_queue_.pop(); | 393 send_queue_.pop(); |
| 370 if (request->status != kIOReturnSuccess) { | 394 if (request->status != kIOReturnSuccess) { |
| 371 if (!request->error_signaled) { | 395 if (!request->error_signaled) { |
| 372 std::stringstream error; | 396 std::stringstream error; |
| 373 error << "Failed to connect bluetooth socket (" | 397 error << "Failed to connect bluetooth socket (" |
| 374 << base::SysNSStringToUTF8([[record_ device] addressString]) | 398 << base::SysNSStringToUTF8( |
| 399 [[rfcomm_channel_ getDevice] addressString]) |
| 375 << "): (" << status << ")"; | 400 << "): (" << status << ")"; |
| 376 request->error_signaled = true; | 401 request->error_signaled = true; |
| 377 request->error_callback.Run(error.str()); | 402 request->error_callback.Run(error.str()); |
| 378 } | 403 } |
| 379 } else { | 404 } else { |
| 380 request->success_callback.Run(request->buffer_size); | 405 request->success_callback.Run(request->buffer_size); |
| 381 } | 406 } |
| 382 } | 407 } |
| 383 | 408 |
| 384 void BluetoothSocketMac::OnChannelClosed( | 409 void BluetoothSocketMac::OnChannelClosed( |
| 385 IOBluetoothRFCOMMChannel* rfcomm_channel) { | 410 IOBluetoothRFCOMMChannel* rfcomm_channel) { |
| 386 DCHECK(thread_checker_.CalledOnValidThread()); | 411 DCHECK(thread_checker_.CalledOnValidThread()); |
| 387 DCHECK_EQ(rfcomm_channel_, rfcomm_channel); | 412 DCHECK_EQ(rfcomm_channel_, rfcomm_channel); |
| 388 | 413 |
| 389 if (receive_callbacks_) { | 414 if (receive_callbacks_) { |
| 390 scoped_ptr<ReceiveCallbacks> temp = receive_callbacks_.Pass(); | 415 scoped_ptr<ReceiveCallbacks> temp = receive_callbacks_.Pass(); |
| 391 temp->error_callback.Run(BluetoothSocket::kDisconnected, | 416 temp->error_callback.Run(BluetoothSocket::kDisconnected, |
| 392 kSocketNotConnected); | 417 kSocketNotConnected); |
| 393 } | 418 } |
| 394 | 419 |
| 395 ReleaseChannel(); | 420 ReleaseChannel(); |
| 396 } | 421 } |
| 397 | 422 |
| 398 } // namespace device | 423 } // namespace device |
| OLD | NEW |