| 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/objc/IOBluetoothDevice.h> |
| 8 #import <IOBluetooth/objc/IOBluetoothRFCOMMChannel.h> | 8 #import <IOBluetooth/objc/IOBluetoothRFCOMMChannel.h> |
| 9 #import <IOBluetooth/objc/IOBluetoothSDPServiceRecord.h> | 9 #import <IOBluetooth/objc/IOBluetoothSDPServiceRecord.h> |
| 10 | 10 |
| 11 #include <limits> | 11 #include <limits> |
| 12 #include <sstream> |
| 12 #include <string> | 13 #include <string> |
| 13 | 14 |
| 14 #include "base/basictypes.h" | 15 #include "base/basictypes.h" |
| 16 #include "base/callback_helpers.h" |
| 15 #include "base/memory/ref_counted.h" | 17 #include "base/memory/ref_counted.h" |
| 16 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
| 17 #include "base/strings/sys_string_conversions.h" | 19 #include "base/strings/sys_string_conversions.h" |
| 20 #include "base/threading/thread_restrictions.h" |
| 18 #include "device/bluetooth/bluetooth_service_record.h" | 21 #include "device/bluetooth/bluetooth_service_record.h" |
| 19 #include "device/bluetooth/bluetooth_service_record_mac.h" | 22 #include "device/bluetooth/bluetooth_service_record_mac.h" |
| 20 #include "net/base/io_buffer.h" | 23 #include "net/base/io_buffer.h" |
| 21 | 24 |
| 22 // Replicate specific 10.7 SDK declarations for building with prior SDKs. | 25 // Replicate specific 10.7 SDK declarations for building with prior SDKs. |
| 23 #if !defined(MAC_OS_X_VERSION_10_7) || \ | 26 #if !defined(MAC_OS_X_VERSION_10_7) || \ |
| 24 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 | 27 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 |
| 25 | 28 |
| 26 @interface IOBluetoothDevice (LionSDKDeclarations) | 29 @interface IOBluetoothDevice (LionSDKDeclarations) |
| 27 - (NSString*)addressString; | 30 - (NSString*)addressString; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 41 | 44 |
| 42 @implementation BluetoothRFCOMMChannelDelegate | 45 @implementation BluetoothRFCOMMChannelDelegate |
| 43 | 46 |
| 44 - (id)initWithSocket:(device::BluetoothSocketMac*)socket { | 47 - (id)initWithSocket:(device::BluetoothSocketMac*)socket { |
| 45 if ((self = [super init])) | 48 if ((self = [super init])) |
| 46 socket_ = socket; | 49 socket_ = socket; |
| 47 | 50 |
| 48 return self; | 51 return self; |
| 49 } | 52 } |
| 50 | 53 |
| 54 - (void)rfcommChannelOpenComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel |
| 55 status:(IOReturn)error { |
| 56 socket_->OnChannelOpened(rfcommChannel, error); |
| 57 } |
| 58 |
| 59 - (void)rfcommChannelWriteComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel |
| 60 refcon:(void*)refcon |
| 61 status:(IOReturn)error { |
| 62 socket_->OnChannelWriteComplete(rfcommChannel, refcon, error); |
| 63 } |
| 64 |
| 51 - (void)rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel | 65 - (void)rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel |
| 52 data:(void*)dataPointer | 66 data:(void*)dataPointer |
| 53 length:(size_t)dataLength { | 67 length:(size_t)dataLength { |
| 54 socket_->OnDataReceived(rfcommChannel, dataPointer, dataLength); | 68 socket_->OnChannelDataReceived(rfcommChannel, dataPointer, dataLength); |
| 69 } |
| 70 |
| 71 - (void)rfcommChannelClosed:(IOBluetoothRFCOMMChannel*)rfcommChannel { |
| 72 socket_->OnChannelClosed(rfcommChannel); |
| 55 } | 73 } |
| 56 | 74 |
| 57 @end | 75 @end |
| 58 | 76 |
| 77 namespace { |
| 78 |
| 79 const char kL2CAPNotSupported[] = "Bluetooth L2CAP protocol is not supported"; |
| 80 const char kSocketConnecting[] = "The socket is currently connecting"; |
| 81 const char kSocketAlreadyConnected[] = "The socket is already connected"; |
| 82 const char kSocketNotConnected[] = "The socket is not connected"; |
| 83 const char kReceivePending[] = "A Receive operation is pending"; |
| 84 |
| 85 template <class T> |
| 86 void empty_queue(std::queue<T>& queue) { |
| 87 std::queue<T> empty; |
| 88 std::swap(queue, empty); |
| 89 } |
| 90 |
| 91 } // namespace |
| 92 |
| 59 namespace device { | 93 namespace device { |
| 60 | 94 |
| 61 BluetoothSocketMac::BluetoothSocketMac(IOBluetoothRFCOMMChannel* rfcomm_channel) | 95 BluetoothSocketMac::SendRequest::SendRequest() |
| 62 : rfcomm_channel_(rfcomm_channel), | 96 : status(kIOReturnSuccess), active_async_writes(0), error_signaled(false) {} |
| 63 delegate_([[BluetoothRFCOMMChannelDelegate alloc] initWithSocket:this]) { | 97 |
| 98 BluetoothSocketMac::SendRequest::~SendRequest() {} |
| 99 |
| 100 BluetoothSocketMac::ReceiveCallbacks::ReceiveCallbacks() {} |
| 101 |
| 102 BluetoothSocketMac::ReceiveCallbacks::~ReceiveCallbacks() {} |
| 103 |
| 104 BluetoothSocketMac::ConnectCallbacks::ConnectCallbacks() {} |
| 105 |
| 106 BluetoothSocketMac::ConnectCallbacks::~ConnectCallbacks() {} |
| 107 |
| 108 // static |
| 109 scoped_refptr<BluetoothSocketMac> BluetoothSocketMac::CreateBluetoothSocket( |
| 110 const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner, |
| 111 IOBluetoothSDPServiceRecord* record) { |
| 112 return new BluetoothSocketMac(ui_task_runner, record); |
| 113 } |
| 114 |
| 115 BluetoothSocketMac::BluetoothSocketMac( |
| 116 const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner, |
| 117 IOBluetoothSDPServiceRecord* record) |
| 118 : ui_task_runner_(ui_task_runner), |
| 119 record_(record), |
| 120 delegate_([[BluetoothRFCOMMChannelDelegate alloc] initWithSocket:this]), |
| 121 rfcomm_channel_(nil) { |
| 122 DCHECK(thread_checker_.CalledOnValidThread()); |
| 123 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 124 [record_ retain]; |
| 125 } |
| 126 |
| 127 BluetoothSocketMac::~BluetoothSocketMac() { |
| 128 DCHECK(thread_checker_.CalledOnValidThread()); |
| 129 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 130 ReleaseChannel(); |
| 131 [delegate_ release]; |
| 132 [record_ release]; |
| 133 } |
| 134 |
| 135 void BluetoothSocketMac::ReleaseChannel() { |
| 136 DCHECK(thread_checker_.CalledOnValidThread()); |
| 137 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 138 if (rfcomm_channel_ != nil) { |
| 139 [rfcomm_channel_ setDelegate:nil]; |
| 140 [rfcomm_channel_ closeChannel]; |
| 141 [rfcomm_channel_ release]; |
| 142 rfcomm_channel_ = nil; |
| 143 } |
| 144 |
| 145 // Closing the channel above prevents the callback delegate from being called |
| 146 // so it is now safe to release all callback state. |
| 147 connect_callbacks_.reset(NULL); |
| 148 receive_callbacks_.reset(NULL); |
| 149 empty_queue(receive_queue_); |
| 150 empty_queue(send_queue_); |
| 151 } |
| 152 |
| 153 void BluetoothSocketMac::Connect( |
| 154 const base::Closure& success_callback, |
| 155 const ErrorCompletionCallback& error_callback) { |
| 156 DCHECK(thread_checker_.CalledOnValidThread()); |
| 157 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 158 |
| 159 if (connecting()) { |
| 160 error_callback.Run(kSocketConnecting); |
| 161 return; |
| 162 } |
| 163 |
| 164 if (rfcomm_channel_ != nil) { |
| 165 error_callback.Run(kSocketAlreadyConnected); |
| 166 return; |
| 167 } |
| 168 |
| 169 uint8 rfcomm_channel_id; |
| 170 IOReturn status = [record_ getRFCOMMChannelID:&rfcomm_channel_id]; |
| 171 if (status != kIOReturnSuccess) { |
| 172 // TODO(youngki) add support for L2CAP sockets as well. |
| 173 error_callback.Run(kL2CAPNotSupported); |
| 174 return; |
| 175 } |
| 176 |
| 177 IOBluetoothDevice* device = [record_ device]; |
| 178 IOBluetoothRFCOMMChannel* rfcomm_channel; |
| 179 status = [device openRFCOMMChannelAsync:&rfcomm_channel |
| 180 withChannelID:rfcomm_channel_id |
| 181 delegate:delegate_]; |
| 182 if (status != kIOReturnSuccess) { |
| 183 std::stringstream error; |
| 184 error << std::string("Failed to connect bluetooth socket (") |
| 185 << base::SysNSStringToUTF8([device addressString]) << "): (" << status |
| 186 << std::string(")"); |
| 187 error_callback.Run(error.str()); |
| 188 return; |
| 189 } |
| 190 |
| 191 connect_callbacks_.reset(new ConnectCallbacks()); |
| 192 connect_callbacks_->success_callback = success_callback; |
| 193 connect_callbacks_->error_callback = error_callback; |
| 194 rfcomm_channel_ = rfcomm_channel; |
| 64 [rfcomm_channel_ setDelegate:delegate_]; | 195 [rfcomm_channel_ setDelegate:delegate_]; |
| 65 ResetIncomingDataBuffer(); | 196 } |
| 66 } | 197 |
| 67 | 198 void BluetoothSocketMac::OnChannelOpened( |
| 68 BluetoothSocketMac::~BluetoothSocketMac() { | 199 IOBluetoothRFCOMMChannel* rfcomm_channel, |
| 69 [rfcomm_channel_ setDelegate:nil]; | 200 IOReturn status) { |
| 70 [rfcomm_channel_ closeChannel]; | 201 DCHECK(thread_checker_.CalledOnValidThread()); |
| 71 [rfcomm_channel_ release]; | 202 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 72 [delegate_ release]; | 203 DCHECK(rfcomm_channel_ == rfcomm_channel); |
| 73 } | 204 DCHECK(connecting()); |
| 74 | 205 |
| 75 // static | 206 scoped_ptr<ConnectCallbacks> temp = connect_callbacks_.Pass(); |
| 76 scoped_refptr<BluetoothSocket> BluetoothSocketMac::CreateBluetoothSocket( | 207 if (status != kIOReturnSuccess) { |
| 77 const BluetoothServiceRecord& service_record) { | 208 ReleaseChannel(); |
| 78 BluetoothSocketMac* bluetooth_socket = NULL; | 209 std::stringstream error; |
| 79 if (service_record.SupportsRfcomm()) { | 210 error << "Failed to connect bluetooth socket (" |
| 80 const BluetoothServiceRecordMac* service_record_mac = | 211 << base::SysNSStringToUTF8([[record_ device] addressString]) << "): (" |
| 81 static_cast<const BluetoothServiceRecordMac*>(&service_record); | 212 << status << ")"; |
| 82 IOBluetoothDevice* device = service_record_mac->GetIOBluetoothDevice(); | 213 temp->error_callback.Run(error.str()); |
| 83 IOBluetoothRFCOMMChannel* rfcomm_channel; | 214 return; |
| 84 IOReturn status = | 215 } |
| 85 [device openRFCOMMChannelAsync:&rfcomm_channel | 216 |
| 86 withChannelID:service_record.rfcomm_channel() | 217 temp->success_callback.Run(); |
| 87 delegate:nil]; | 218 } |
| 88 if (status == kIOReturnSuccess) { | 219 |
| 89 bluetooth_socket = new BluetoothSocketMac(rfcomm_channel); | 220 void BluetoothSocketMac::Close() { |
| 90 } else { | 221 DCHECK(thread_checker_.CalledOnValidThread()); |
| 91 LOG(ERROR) << "Failed to connect bluetooth socket (" | 222 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 92 << service_record.address() << "): (" << status << ")"; | 223 |
| 93 } | 224 ReleaseChannel(); |
| 94 } | 225 } |
| 95 // TODO(youngki): add support for L2CAP sockets as well. | |
| 96 | |
| 97 return scoped_refptr<BluetoothSocketMac>(bluetooth_socket); | |
| 98 } | |
| 99 | |
| 100 // static | |
| 101 scoped_refptr<BluetoothSocket> BluetoothSocketMac::CreateBluetoothSocket( | |
| 102 IOBluetoothSDPServiceRecord* record) { | |
| 103 BluetoothSocketMac* bluetooth_socket = NULL; | |
| 104 uint8 rfcomm_channel_id; | |
| 105 if ([record getRFCOMMChannelID:&rfcomm_channel_id] == kIOReturnSuccess) { | |
| 106 IOBluetoothDevice* device = [record device]; | |
| 107 IOBluetoothRFCOMMChannel* rfcomm_channel; | |
| 108 IOReturn status = | |
| 109 [device openRFCOMMChannelAsync:&rfcomm_channel | |
| 110 withChannelID:rfcomm_channel_id | |
| 111 delegate:nil]; | |
| 112 if (status == kIOReturnSuccess) { | |
| 113 bluetooth_socket = new BluetoothSocketMac(rfcomm_channel); | |
| 114 } else { | |
| 115 LOG(ERROR) << "Failed to connect bluetooth socket (" | |
| 116 << base::SysNSStringToUTF8([device addressString]) << "): (" << status | |
| 117 << ")"; | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 // TODO(youngki): Add support for L2CAP sockets as well. | |
| 122 | |
| 123 return scoped_refptr<BluetoothSocketMac>(bluetooth_socket); | |
| 124 } | |
| 125 | |
| 126 void BluetoothSocketMac::Close() { NOTIMPLEMENTED(); } | |
| 127 | 226 |
| 128 void BluetoothSocketMac::Disconnect(const base::Closure& callback) { | 227 void BluetoothSocketMac::Disconnect(const base::Closure& callback) { |
| 129 NOTIMPLEMENTED(); | 228 DCHECK(thread_checker_.CalledOnValidThread()); |
| 229 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 230 |
| 231 ReleaseChannel(); |
| 232 callback.Run(); |
| 130 } | 233 } |
| 131 | 234 |
| 132 void BluetoothSocketMac::Receive( | 235 void BluetoothSocketMac::Receive( |
| 133 int count, | 236 int count, |
| 134 const ReceiveCompletionCallback& success_callback, | 237 const ReceiveCompletionCallback& success_callback, |
| 135 const ReceiveErrorCompletionCallback& error_callback) { | 238 const ReceiveErrorCompletionCallback& error_callback) { |
| 136 NOTIMPLEMENTED(); | 239 DCHECK(thread_checker_.CalledOnValidThread()); |
| 240 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 241 |
| 242 if (connecting()) { |
| 243 error_callback.Run(BluetoothSocket::kSystemError, kSocketConnecting); |
| 244 return; |
| 245 } |
| 246 |
| 247 if (rfcomm_channel_ == nil) { |
| 248 error_callback.Run(BluetoothSocket::kDisconnected, kSocketNotConnected); |
| 249 return; |
| 250 } |
| 251 |
| 252 // Only one pending read at a time |
| 253 if (receive_callbacks_) { |
| 254 error_callback.Run(BluetoothSocket::kIOPending, kReceivePending); |
| 255 return; |
| 256 } |
| 257 |
| 258 // If there is at least one packet, consume it and succeed right away. |
| 259 if (!receive_queue_.empty()) { |
| 260 scoped_refptr<net::IOBufferWithSize> buffer = receive_queue_.front(); |
| 261 receive_queue_.pop(); |
| 262 success_callback.Run(buffer->size(), buffer); |
| 263 return; |
| 264 } |
| 265 |
| 266 // Set the receive callback to use when data is received. |
| 267 receive_callbacks_.reset(new ReceiveCallbacks()); |
| 268 receive_callbacks_->success_callback = success_callback; |
| 269 receive_callbacks_->error_callback = error_callback; |
| 270 } |
| 271 |
| 272 void BluetoothSocketMac::OnChannelDataReceived( |
| 273 IOBluetoothRFCOMMChannel* rfcomm_channel, |
| 274 void* data, |
| 275 size_t length) { |
| 276 DCHECK(thread_checker_.CalledOnValidThread()); |
| 277 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 278 DCHECK(rfcomm_channel_ == rfcomm_channel); |
| 279 DCHECK(!connecting()); |
| 280 CHECK_LT(length, static_cast<size_t>(std::numeric_limits<int>::max())); |
| 281 |
| 282 int data_size = static_cast<int>(length); |
| 283 scoped_refptr<net::IOBufferWithSize> buffer( |
| 284 new net::IOBufferWithSize(data_size)); |
| 285 memcpy(buffer->data(), data, buffer->size()); |
| 286 |
| 287 // If there is a pending read callback, call it now. |
| 288 if (receive_callbacks_) { |
| 289 scoped_ptr<ReceiveCallbacks> temp = receive_callbacks_.Pass(); |
| 290 temp->success_callback.Run(buffer->size(), buffer); |
| 291 return; |
| 292 } |
| 293 |
| 294 // Otherwise, enqueue the buffer for later use |
| 295 receive_queue_.push(buffer); |
| 137 } | 296 } |
| 138 | 297 |
| 139 void BluetoothSocketMac::Send(scoped_refptr<net::IOBuffer> buffer, | 298 void BluetoothSocketMac::Send(scoped_refptr<net::IOBuffer> buffer, |
| 140 int buffer_size, | 299 int buffer_size, |
| 141 const SendCompletionCallback& success_callback, | 300 const SendCompletionCallback& success_callback, |
| 142 const ErrorCompletionCallback& error_callback) { | 301 const ErrorCompletionCallback& error_callback) { |
| 143 NOTIMPLEMENTED(); | 302 DCHECK(thread_checker_.CalledOnValidThread()); |
| 144 } | 303 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 145 | 304 |
| 146 #if 0 | 305 if (connecting()) { |
| 147 bool BluetoothSocketMac::Receive(net::GrowableIOBuffer* buffer) { | 306 error_callback.Run(kSocketConnecting); |
| 148 CHECK(buffer->offset() == 0); | 307 return; |
| 149 int length = incoming_data_buffer_->offset(); | 308 } |
| 150 if (length > 0) { | 309 |
| 151 buffer->SetCapacity(length); | 310 if (rfcomm_channel_ == nil) { |
| 152 memcpy(buffer->data(), incoming_data_buffer_->StartOfBuffer(), length); | 311 error_callback.Run(kSocketNotConnected); |
| 153 buffer->set_offset(length); | 312 return; |
| 154 | 313 } |
| 155 ResetIncomingDataBuffer(); | 314 |
| 156 } | 315 // Create and enqueue request in preparation of async writes. |
| 157 return true; | 316 linked_ptr<SendRequest> request(new SendRequest()); |
| 158 } | 317 request->buffer_size = buffer_size; |
| 159 | 318 request->success_callback = success_callback; |
| 160 bool BluetoothSocketMac::Send(net::DrainableIOBuffer* buffer) { | 319 request->error_callback = error_callback; |
| 161 int bytes_written = buffer->BytesRemaining(); | 320 send_queue_.push(request); |
| 162 IOReturn status = [rfcomm_channel_ writeAsync:buffer->data() | 321 |
| 163 length:bytes_written | 322 // |writeAsync| accepts buffers of max. mtu bytes per call, so we need to emit |
| 164 refcon:nil]; | 323 // multiple write operations if buffer_size > mtu. |
| 324 BluetoothRFCOMMMTU mtu = [rfcomm_channel_ getMTU]; |
| 325 scoped_refptr<net::DrainableIOBuffer> send_buffer( |
| 326 new net::DrainableIOBuffer(buffer, buffer_size)); |
| 327 while (send_buffer->BytesRemaining() > 0) { |
| 328 int byte_count = send_buffer->BytesRemaining(); |
| 329 if (byte_count > mtu) |
| 330 byte_count = mtu; |
| 331 IOReturn status = [rfcomm_channel_ writeAsync:send_buffer->data() |
| 332 length:byte_count |
| 333 refcon:request.get()]; |
| 334 if (status != kIOReturnSuccess) { |
| 335 std::stringstream error; |
| 336 error << "Failed to connect bluetooth socket (" |
| 337 << base::SysNSStringToUTF8([[record_ device] addressString]) |
| 338 << "): (" << status << ")"; |
| 339 // Remember the first error only |
| 340 if (request->status == kIOReturnSuccess) |
| 341 request->status = status; |
| 342 request->error_signaled = true; |
| 343 request->error_callback.Run(error.str()); |
| 344 // We may have failed to issue any write operation. In that case, there |
| 345 // will be no corresponding completion callback for this particular |
| 346 // request, so we must forget about it now. |
| 347 if (request->active_async_writes == 0) { |
| 348 send_queue_.pop(); |
| 349 } |
| 350 return; |
| 351 } |
| 352 |
| 353 request->active_async_writes++; |
| 354 send_buffer->DidConsume(byte_count); |
| 355 } |
| 356 } |
| 357 |
| 358 void BluetoothSocketMac::OnChannelWriteComplete( |
| 359 IOBluetoothRFCOMMChannel* rfcomm_channel, |
| 360 void* refcon, |
| 361 IOReturn status) { |
| 362 DCHECK(thread_checker_.CalledOnValidThread()); |
| 363 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 364 |
| 365 // Note: We use "CHECK" below to ensure we never run into unforeseen |
| 366 // occurrences of asynchronous callbacks, which could lead to data |
| 367 // corruption. |
| 368 CHECK(rfcomm_channel_ == rfcomm_channel); |
| 369 CHECK(static_cast<SendRequest*>(refcon) == send_queue_.front().get()); |
| 370 |
| 371 // Keep a local linked_ptr to avoid releasing the request too early if we end |
| 372 // up removing it from the queue. |
| 373 linked_ptr<SendRequest> request = send_queue_.front(); |
| 374 |
| 375 // Remember the first error only |
| 165 if (status != kIOReturnSuccess) { | 376 if (status != kIOReturnSuccess) { |
| 166 error_message_ = base::StringPrintf( | 377 if (request->status == kIOReturnSuccess) |
| 167 "Failed to send data. IOReturn code: %u", status); | 378 request->status = status; |
| 168 return false; | 379 } |
| 169 } | 380 |
| 170 | 381 // Figure out if we are done with this async request |
| 171 buffer->DidConsume(bytes_written); | 382 request->active_async_writes--; |
| 172 return true; | 383 if (request->active_async_writes > 0) |
| 173 } | 384 return; |
| 174 | 385 |
| 175 std::string BluetoothSocketMac::GetLastErrorMessage() const { | 386 // If this was the last active async write for this request, remove it from |
| 176 return error_message_; | 387 // the queue and call the appropriate callback associated to the request. |
| 177 } | 388 send_queue_.pop(); |
| 178 #endif | 389 if (request->status != kIOReturnSuccess) { |
| 179 void BluetoothSocketMac::OnDataReceived( | 390 if (!request->error_signaled) { |
| 180 IOBluetoothRFCOMMChannel* rfcomm_channel, void* data, size_t length) { | 391 std::stringstream error; |
| 392 error << "Failed to connect bluetooth socket (" |
| 393 << base::SysNSStringToUTF8([[record_ device] addressString]) |
| 394 << "): (" << status << ")"; |
| 395 request->error_signaled = true; |
| 396 request->error_callback.Run(error.str()); |
| 397 } |
| 398 } else { |
| 399 request->success_callback.Run(request->buffer_size); |
| 400 } |
| 401 } |
| 402 |
| 403 void BluetoothSocketMac::OnChannelClosed( |
| 404 IOBluetoothRFCOMMChannel* rfcomm_channel) { |
| 405 DCHECK(thread_checker_.CalledOnValidThread()); |
| 406 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 181 DCHECK(rfcomm_channel_ == rfcomm_channel); | 407 DCHECK(rfcomm_channel_ == rfcomm_channel); |
| 182 CHECK_LT(length, static_cast<size_t>(std::numeric_limits<int>::max())); | 408 |
| 183 int data_size = static_cast<int>(length); | 409 if (receive_callbacks_) { |
| 184 if (incoming_data_buffer_->RemainingCapacity() < data_size) { | 410 scoped_ptr<ReceiveCallbacks> temp = receive_callbacks_.Pass(); |
| 185 int additional_capacity = | 411 temp->error_callback.Run(BluetoothSocket::kDisconnected, |
| 186 std::max(data_size, incoming_data_buffer_->capacity()); | 412 kSocketNotConnected); |
| 187 CHECK_LT( | 413 } |
| 188 additional_capacity, | 414 |
| 189 std::numeric_limits<int>::max() - incoming_data_buffer_->capacity()); | 415 ReleaseChannel(); |
| 190 incoming_data_buffer_->SetCapacity( | |
| 191 incoming_data_buffer_->capacity() + additional_capacity); | |
| 192 } | |
| 193 memcpy(incoming_data_buffer_->data(), data, data_size); | |
| 194 incoming_data_buffer_->set_offset( | |
| 195 incoming_data_buffer_->offset() + data_size); | |
| 196 } | |
| 197 | |
| 198 void BluetoothSocketMac::ResetIncomingDataBuffer() { | |
| 199 incoming_data_buffer_ = new net::GrowableIOBuffer(); | |
| 200 incoming_data_buffer_->SetCapacity(1024); | |
| 201 } | 416 } |
| 202 | 417 |
| 203 } // namespace device | 418 } // namespace device |
| OLD | NEW |