Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(214)

Side by Side Diff: device/bluetooth/bluetooth_socket_mac.mm

Issue 328903002: Factor out a BluetoothChannelMac base class and a BluetoothRfcommChannelMac subclass. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: git-add new files Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « device/bluetooth/bluetooth_socket_mac.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/IOBluetooth.h> 7 #import <IOBluetooth/IOBluetooth.h>
8 8
9 #include <limits> 9 #include <limits>
10 #include <sstream> 10 #include <sstream>
11 #include <string> 11 #include <string>
12 12
13 #include "base/basictypes.h" 13 #include "base/basictypes.h"
14 #include "base/bind.h" 14 #include "base/bind.h"
15 #include "base/callback_helpers.h" 15 #include "base/callback_helpers.h"
16 #include "base/mac/scoped_cftyperef.h" 16 #include "base/mac/scoped_cftyperef.h"
17 #include "base/memory/ref_counted.h" 17 #include "base/memory/ref_counted.h"
18 #include "base/numerics/safe_conversions.h" 18 #include "base/numerics/safe_conversions.h"
19 #include "base/strings/stringprintf.h" 19 #include "base/strings/stringprintf.h"
20 #include "base/strings/string_number_conversions.h" 20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/sys_string_conversions.h" 21 #include "base/strings/sys_string_conversions.h"
22 #include "base/threading/thread_restrictions.h" 22 #include "base/threading/thread_restrictions.h"
23 #include "device/bluetooth/bluetooth_adapter.h" 23 #include "device/bluetooth/bluetooth_adapter.h"
24 #include "device/bluetooth/bluetooth_channel_mac.h"
24 #include "device/bluetooth/bluetooth_device.h" 25 #include "device/bluetooth/bluetooth_device.h"
25 #include "device/bluetooth/bluetooth_device_mac.h" 26 #include "device/bluetooth/bluetooth_device_mac.h"
27 #include "device/bluetooth/bluetooth_rfcomm_channel_mac.h"
26 #include "net/base/io_buffer.h" 28 #include "net/base/io_buffer.h"
27 #include "net/base/net_errors.h" 29 #include "net/base/net_errors.h"
28 30
29 // Replicate specific 10.7 SDK declarations for building with prior SDKs. 31 // Replicate specific 10.7 SDK declarations for building with prior SDKs.
30 #if !defined(MAC_OS_X_VERSION_10_7) || \ 32 #if !defined(MAC_OS_X_VERSION_10_7) || \
31 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 33 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
32 34
33 @interface IOBluetoothDevice (LionSDKDeclarations) 35 @interface IOBluetoothDevice (LionSDKDeclarations)
34 - (IOReturn)performSDPQuery:(id)target uuids:(NSArray*)uuids; 36 - (IOReturn)performSDPQuery:(id)target uuids:(NSArray*)uuids;
35 @end 37 @end
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 channel:(IOBluetoothRFCOMMChannel*)rfcommChannel { 136 channel:(IOBluetoothRFCOMMChannel*)rfcommChannel {
135 if (notification != rfcommNewChannelNotification_) { 137 if (notification != rfcommNewChannelNotification_) {
136 // This case is reachable if there are pre-existing RFCOMM channels open at 138 // This case is reachable if there are pre-existing RFCOMM channels open at
137 // the time that the listener is created. In that case, each existing 139 // the time that the listener is created. In that case, each existing
138 // channel calls into this method with a different notification than the one 140 // channel calls into this method with a different notification than the one
139 // this class registered with. Ignore those; this class is only interested 141 // this class registered with. Ignore those; this class is only interested
140 // in channels that have opened since it registered for notifications. 142 // in channels that have opened since it registered for notifications.
141 return; 143 return;
142 } 144 }
143 145
144 socket_->OnRfcommChannelOpened(rfcommChannel); 146 socket_->OnChannelOpened(scoped_ptr<device::BluetoothChannelMac>(
147 new device::BluetoothRfcommChannelMac(NULL, [rfcommChannel retain])));
145 } 148 }
146 149
147 @end 150 @end
148
149 // A simple delegate class for an open RFCOMM channel that forwards methods to
150 // its wrapped |socket_|.
151 @interface BluetoothRfcommChannelDelegate
152 : NSObject <IOBluetoothRFCOMMChannelDelegate> {
153 @private
154 device::BluetoothSocketMac* socket_; // weak
155 }
156
157 - (id)initWithSocket:(device::BluetoothSocketMac*)socket;
158
159 @end
160
161 @implementation BluetoothRfcommChannelDelegate
162
163 - (id)initWithSocket:(device::BluetoothSocketMac*)socket {
164 if ((self = [super init]))
165 socket_ = socket;
166
167 return self;
168 }
169
170 - (void)rfcommChannelOpenComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel
171 status:(IOReturn)error {
172 socket_->OnRfcommChannelOpenComplete(rfcommChannel, error);
173 }
174
175 - (void)rfcommChannelWriteComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel
176 refcon:(void*)refcon
177 status:(IOReturn)error {
178 socket_->OnRfcommChannelWriteComplete(rfcommChannel, refcon, error);
179 }
180
181 - (void)rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel
182 data:(void*)dataPointer
183 length:(size_t)dataLength {
184 socket_->OnRfcommChannelDataReceived(rfcommChannel, dataPointer, dataLength);
185 }
186
187 - (void)rfcommChannelClosed:(IOBluetoothRFCOMMChannel*)rfcommChannel {
188 socket_->OnRfcommChannelClosed(rfcommChannel);
189 }
190
191 @end
192 151
193 namespace device { 152 namespace device {
194 namespace { 153 namespace {
195 154
196 // It's safe to use 0 to represent an unregistered service, as implied by the 155 // It's safe to use 0 to represent an unregistered service, as implied by the
197 // documentation at [ http://goo.gl/YRtCkF ]. 156 // documentation at [ http://goo.gl/YRtCkF ].
198 const BluetoothSDPServiceRecordHandle kInvalidServiceRecordHandle = 0; 157 const BluetoothSDPServiceRecordHandle kInvalidServiceRecordHandle = 0;
199 158
200 const char kL2capNotSupported[] = "Bluetooth L2CAP protocol is not supported"; 159 const char kL2capNotSupported[] = "Bluetooth L2CAP protocol is not supported";
201 const char kInvalidOrUsedChannel[] = "Invalid channel or already in use"; 160 const char kInvalidOrUsedChannel[] = "Invalid channel or already in use";
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 const BluetoothUUID& uuid, 288 const BluetoothUUID& uuid,
330 const base::Closure& success_callback, 289 const base::Closure& success_callback,
331 const ErrorCompletionCallback& error_callback) { 290 const ErrorCompletionCallback& error_callback) {
332 DCHECK(thread_checker_.CalledOnValidThread()); 291 DCHECK(thread_checker_.CalledOnValidThread());
333 292
334 uuid_ = uuid; 293 uuid_ = uuid;
335 294
336 // Perform an SDP query on the |device| to refresh the cache, in case the 295 // Perform an SDP query on the |device| to refresh the cache, in case the
337 // services that the |device| advertises have changed since the previous 296 // services that the |device| advertises have changed since the previous
338 // query. 297 // query.
339 VLOG(1) << BluetoothDeviceMac::GetDeviceAddress(device) << " " 298 DVLOG(1) << BluetoothDeviceMac::GetDeviceAddress(device) << " "
340 << uuid_.canonical_value() << ": Sending SDP query."; 299 << uuid_.canonical_value() << ": Sending SDP query.";
341 SDPQueryListener* listener = 300 SDPQueryListener* listener =
342 [[SDPQueryListener alloc] initWithSocket:this 301 [[SDPQueryListener alloc] initWithSocket:this
343 device:device 302 device:device
344 success_callback:success_callback 303 success_callback:success_callback
345 error_callback:error_callback]; 304 error_callback:error_callback];
346 [device performSDPQuery:[listener autorelease] 305 [device performSDPQuery:[listener autorelease]
347 uuids:@[GetIOBluetoothSDPUUID(uuid_)]]; 306 uuids:@[GetIOBluetoothSDPUUID(uuid_)]];
348 } 307 }
349 308
350 void BluetoothSocketMac::ListenUsingRfcomm( 309 void BluetoothSocketMac::ListenUsingRfcomm(
351 scoped_refptr<BluetoothAdapter> adapter, 310 scoped_refptr<BluetoothAdapter> adapter,
352 const BluetoothUUID& uuid, 311 const BluetoothUUID& uuid,
353 int channel_id, 312 int channel_id,
354 const base::Closure& success_callback, 313 const base::Closure& success_callback,
355 const ErrorCompletionCallback& error_callback) { 314 const ErrorCompletionCallback& error_callback) {
356 DCHECK(thread_checker_.CalledOnValidThread()); 315 DCHECK(thread_checker_.CalledOnValidThread());
357 316
358 adapter_ = adapter; 317 adapter_ = adapter;
359 uuid_ = uuid; 318 uuid_ = uuid;
360 319
361 VLOG(1) << uuid_.canonical_value() << ": Registering service."; 320 DVLOG(1) << uuid_.canonical_value() << ": Registering service.";
362 BluetoothRFCOMMChannelID registered_channel_id; 321 BluetoothRFCOMMChannelID registered_channel_id;
363 service_record_handle_ = 322 service_record_handle_ =
364 RegisterRfcommService(uuid, channel_id, &registered_channel_id); 323 RegisterRfcommService(uuid, channel_id, &registered_channel_id);
365 if (service_record_handle_ == kInvalidServiceRecordHandle) { 324 if (service_record_handle_ == kInvalidServiceRecordHandle) {
366 error_callback.Run(kInvalidOrUsedChannel); 325 error_callback.Run(kInvalidOrUsedChannel);
367 return; 326 return;
368 } 327 }
369 328
370 rfcomm_connection_listener_.reset( 329 rfcomm_connection_listener_.reset(
371 [[BluetoothRfcommConnectionListener alloc] 330 [[BluetoothRfcommConnectionListener alloc]
(...skipping 12 matching lines...) Expand all
384 // TODO(isherman): Implment support for L2CAP sockets. 343 // TODO(isherman): Implment support for L2CAP sockets.
385 error_callback.Run(kL2capNotSupported); 344 error_callback.Run(kL2capNotSupported);
386 } 345 }
387 346
388 void BluetoothSocketMac::OnSDPQueryComplete( 347 void BluetoothSocketMac::OnSDPQueryComplete(
389 IOReturn status, 348 IOReturn status,
390 IOBluetoothDevice* device, 349 IOBluetoothDevice* device,
391 const base::Closure& success_callback, 350 const base::Closure& success_callback,
392 const ErrorCompletionCallback& error_callback) { 351 const ErrorCompletionCallback& error_callback) {
393 DCHECK(thread_checker_.CalledOnValidThread()); 352 DCHECK(thread_checker_.CalledOnValidThread());
394 VLOG(1) << BluetoothDeviceMac::GetDeviceAddress(device) << " " 353 DVLOG(1) << BluetoothDeviceMac::GetDeviceAddress(device) << " "
395 << uuid_.canonical_value() << ": SDP query complete."; 354 << uuid_.canonical_value() << ": SDP query complete.";
396 355
397 if (status != kIOReturnSuccess) { 356 if (status != kIOReturnSuccess) {
398 error_callback.Run(kSDPQueryFailed); 357 error_callback.Run(kSDPQueryFailed);
399 return; 358 return;
400 } 359 }
401 360
402 IOBluetoothSDPServiceRecord* record = [device 361 IOBluetoothSDPServiceRecord* record = [device
403 getServiceRecordForUUID:GetIOBluetoothSDPUUID(uuid_)]; 362 getServiceRecordForUUID:GetIOBluetoothSDPUUID(uuid_)];
404 if (record == nil) { 363 if (record == nil) {
405 error_callback.Run(kProfileNotFound); 364 error_callback.Run(kProfileNotFound);
406 return; 365 return;
407 } 366 }
408 367
409 if (is_connecting()) { 368 if (is_connecting()) {
410 error_callback.Run(kSocketConnecting); 369 error_callback.Run(kSocketConnecting);
411 return; 370 return;
412 } 371 }
413 372
414 if (rfcomm_channel_) { 373 if (channel_) {
415 error_callback.Run(kSocketAlreadyConnected); 374 error_callback.Run(kSocketAlreadyConnected);
416 return; 375 return;
417 } 376 }
418 377
419 uint8 rfcomm_channel_id; 378 uint8 rfcomm_channel_id;
420 status = [record getRFCOMMChannelID:&rfcomm_channel_id]; 379 status = [record getRFCOMMChannelID:&rfcomm_channel_id];
421 if (status != kIOReturnSuccess) { 380 if (status != kIOReturnSuccess) {
422 // TODO(isherman): Add support for L2CAP sockets as well. 381 // TODO(isherman): Add support for L2CAP sockets as well.
423 error_callback.Run(kL2capNotSupported); 382 error_callback.Run(kL2capNotSupported);
424 return; 383 return;
425 } 384 }
426 385
427 VLOG(1) << BluetoothDeviceMac::GetDeviceAddress(device) << " " 386 DVLOG(1) << BluetoothDeviceMac::GetDeviceAddress(device) << " "
428 << uuid_.canonical_value() << ": Opening RFCOMM channel: " 387 << uuid_.canonical_value() << ": Opening RFCOMM channel: "
429 << rfcomm_channel_id; 388 << rfcomm_channel_id;
430 389
431 // Note: It's important to set the connect callbacks *prior* to opening the 390 // Note: It's important to set the connect callbacks *prior* to opening the
432 // channel as the delegate is passed in and can synchronously call into 391 // channel as the delegate is passed in and can synchronously call into
433 // OnRfcommChannelOpenComplete(). 392 // OnChannelOpenComplete().
434 connect_callbacks_.reset(new ConnectCallbacks()); 393 connect_callbacks_.reset(new ConnectCallbacks());
435 connect_callbacks_->success_callback = success_callback; 394 connect_callbacks_->success_callback = success_callback;
436 connect_callbacks_->error_callback = error_callback; 395 connect_callbacks_->error_callback = error_callback;
437 396
438 rfcomm_channel_delegate_.reset( 397 channel_ = BluetoothRfcommChannelMac::OpenAsync(
439 [[BluetoothRfcommChannelDelegate alloc] initWithSocket:this]); 398 this, device, rfcomm_channel_id, &status);
440
441 IOBluetoothRFCOMMChannel* rfcomm_channel;
442 status = [device openRFCOMMChannelAsync:&rfcomm_channel
443 withChannelID:rfcomm_channel_id
444 delegate:rfcomm_channel_delegate_];
445 if (status != kIOReturnSuccess) { 399 if (status != kIOReturnSuccess) {
446 std::stringstream error; 400 std::stringstream error;
447 error << "Failed to connect bluetooth socket (" 401 error << "Failed to connect bluetooth socket ("
448 << BluetoothDeviceMac::GetDeviceAddress(device) << "): (" << status 402 << BluetoothDeviceMac::GetDeviceAddress(device) << "): (" << status
449 << ")"; 403 << ")";
450 error_callback.Run(error.str()); 404 error_callback.Run(error.str());
451 return; 405 return;
452 } 406 }
453 407
454 VLOG(2) << BluetoothDeviceMac::GetDeviceAddress(device) << " " 408 DVLOG(2) << BluetoothDeviceMac::GetDeviceAddress(device) << " "
455 << uuid_.canonical_value() 409 << uuid_.canonical_value()
456 << ": RFCOMM channel opening in background."; 410 << ": RFCOMM channel opening in background.";
457 rfcomm_channel_.reset([rfcomm_channel retain]);
458 } 411 }
459 412
460 void BluetoothSocketMac::OnRfcommChannelOpened( 413 void BluetoothSocketMac::OnChannelOpened(
461 IOBluetoothRFCOMMChannel* rfcomm_channel) { 414 scoped_ptr<BluetoothChannelMac> channel) {
462 DCHECK(thread_checker_.CalledOnValidThread()); 415 DCHECK(thread_checker_.CalledOnValidThread());
463 VLOG(1) << uuid_.canonical_value() << ": Incoming RFCOMM channel pending."; 416 DVLOG(1) << uuid_.canonical_value() << ": Incoming channel pending.";
464 417
465 // TODO(isherman): The channel ought to already be retained. Stop 418 accept_queue_.push(linked_ptr<BluetoothChannelMac>(channel.release()));
466 // over-retaining it.
467 base::scoped_nsobject<IOBluetoothRFCOMMChannel>
468 scoped_channel([rfcomm_channel retain]);
469 accept_queue_.push(scoped_channel);
470 if (accept_request_) 419 if (accept_request_)
471 AcceptConnectionRequest(); 420 AcceptConnectionRequest();
472 421
473 // TODO(isherman): Test whether these TODOs are still relevant. 422 // TODO(isherman): Test whether these TODOs are still relevant.
474 // TODO(isherman): Currently, both the profile and the socket remain alive 423 // TODO(isherman): Currently, both the profile and the socket remain alive
475 // even after the app that requested them is closed. That's not great, as a 424 // even after the app that requested them is closed. That's not great, as a
476 // misbehaving app could saturate all of the system's RFCOMM channels, and 425 // misbehaving app could saturate all of the system's RFCOMM channels, and
477 // then they would not be freed until the user restarts Chrome. 426 // then they would not be freed until the user restarts Chrome.
478 // http://crbug.com/367316 427 // http://crbug.com/367316
479 // TODO(isherman): Likewise, the socket currently remains alive even if the 428 // TODO(isherman): Likewise, the socket currently remains alive even if the
480 // underlying rfcomm_channel is closed, e.g. via the client disconnecting, or 429 // underlying rfcomm_channel is closed, e.g. via the client disconnecting, or
481 // the user closing the Bluetooth connection via the system menu. This 430 // the user closing the Bluetooth connection via the system menu. This
482 // functions essentially as a minor memory leak. 431 // functions essentially as a minor memory leak.
483 // http://crbug.com/367319 432 // http://crbug.com/367319
484 } 433 }
485 434
486 void BluetoothSocketMac::OnRfcommChannelOpenComplete( 435 void BluetoothSocketMac::OnChannelOpenComplete(
487 IOBluetoothRFCOMMChannel* rfcomm_channel, 436 const std::string& device_address,
488 IOReturn status) { 437 IOReturn status) {
489 DCHECK(thread_checker_.CalledOnValidThread()); 438 DCHECK(thread_checker_.CalledOnValidThread());
490 // TODO(isherman): Come back to these DCHECKs -- I'm not completely convinced 439 DCHECK(is_connecting());
491 // that they're correct.
492 if (rfcomm_channel_) {
493 // Client connection complete.
494 DCHECK_EQ(rfcomm_channel_, rfcomm_channel);
495 DCHECK(is_connecting());
496 } else {
497 // A new client has connected to this server socket.
498 DCHECK_EQ(kIOReturnSuccess, status);
499 }
500 440
501 VLOG(1) << BluetoothDeviceMac::GetDeviceAddress([rfcomm_channel getDevice]) 441 DVLOG(1) << device_address << " " << uuid_.canonical_value()
502 << " " << uuid_.canonical_value() 442 << ": channel open complete.";
503 << ": RFCOMM channel open complete.";
504
505 443
506 scoped_ptr<ConnectCallbacks> temp = connect_callbacks_.Pass(); 444 scoped_ptr<ConnectCallbacks> temp = connect_callbacks_.Pass();
507 if (status != kIOReturnSuccess) { 445 if (status != kIOReturnSuccess) {
508 ReleaseChannel(); 446 ReleaseChannel();
509 std::stringstream error; 447 std::stringstream error;
510 error << "Failed to connect bluetooth socket (" 448 error << "Failed to connect bluetooth socket (" << device_address << "): ("
511 << BluetoothDeviceMac::GetDeviceAddress([rfcomm_channel getDevice]) 449 << status << ")";
512 << "): (" << status << ")";
513 temp->error_callback.Run(error.str()); 450 temp->error_callback.Run(error.str());
514 return; 451 return;
515 } 452 }
516 453
517 temp->success_callback.Run(); 454 temp->success_callback.Run();
518 } 455 }
519 456
520 void BluetoothSocketMac::Close() { 457 void BluetoothSocketMac::Close() {
521 DCHECK(thread_checker_.CalledOnValidThread()); 458 DCHECK(thread_checker_.CalledOnValidThread());
522 459
523 if (rfcomm_channel_) 460 if (channel_)
524 ReleaseChannel(); 461 ReleaseChannel();
525 else if (service_record_handle_ != kInvalidServiceRecordHandle) 462 else if (service_record_handle_ != kInvalidServiceRecordHandle)
526 ReleaseListener(); 463 ReleaseListener();
527 } 464 }
528 465
529 void BluetoothSocketMac::Disconnect(const base::Closure& callback) { 466 void BluetoothSocketMac::Disconnect(const base::Closure& callback) {
530 DCHECK(thread_checker_.CalledOnValidThread()); 467 DCHECK(thread_checker_.CalledOnValidThread());
531 468
532 Close(); 469 Close();
533 callback.Run(); 470 callback.Run();
534 } 471 }
535 472
536 void BluetoothSocketMac::Receive( 473 void BluetoothSocketMac::Receive(
537 int /* buffer_size */, 474 int /* buffer_size */,
538 const ReceiveCompletionCallback& success_callback, 475 const ReceiveCompletionCallback& success_callback,
539 const ReceiveErrorCompletionCallback& error_callback) { 476 const ReceiveErrorCompletionCallback& error_callback) {
540 DCHECK(thread_checker_.CalledOnValidThread()); 477 DCHECK(thread_checker_.CalledOnValidThread());
541 478
542 if (is_connecting()) { 479 if (is_connecting()) {
543 error_callback.Run(BluetoothSocket::kSystemError, kSocketConnecting); 480 error_callback.Run(BluetoothSocket::kSystemError, kSocketConnecting);
544 return; 481 return;
545 } 482 }
546 483
547 if (!rfcomm_channel_) { 484 if (!channel_) {
548 error_callback.Run(BluetoothSocket::kDisconnected, kSocketNotConnected); 485 error_callback.Run(BluetoothSocket::kDisconnected, kSocketNotConnected);
549 return; 486 return;
550 } 487 }
551 488
552 // Only one pending read at a time 489 // Only one pending read at a time
553 if (receive_callbacks_) { 490 if (receive_callbacks_) {
554 error_callback.Run(BluetoothSocket::kIOPending, kReceivePending); 491 error_callback.Run(BluetoothSocket::kIOPending, kReceivePending);
555 return; 492 return;
556 } 493 }
557 494
558 // If there is at least one packet, consume it and succeed right away. 495 // If there is at least one packet, consume it and succeed right away.
559 if (!receive_queue_.empty()) { 496 if (!receive_queue_.empty()) {
560 scoped_refptr<net::IOBufferWithSize> buffer = receive_queue_.front(); 497 scoped_refptr<net::IOBufferWithSize> buffer = receive_queue_.front();
561 receive_queue_.pop(); 498 receive_queue_.pop();
562 success_callback.Run(buffer->size(), buffer); 499 success_callback.Run(buffer->size(), buffer);
563 return; 500 return;
564 } 501 }
565 502
566 // Set the receive callback to use when data is received. 503 // Set the receive callback to use when data is received.
567 receive_callbacks_.reset(new ReceiveCallbacks()); 504 receive_callbacks_.reset(new ReceiveCallbacks());
568 receive_callbacks_->success_callback = success_callback; 505 receive_callbacks_->success_callback = success_callback;
569 receive_callbacks_->error_callback = error_callback; 506 receive_callbacks_->error_callback = error_callback;
570 } 507 }
571 508
572 void BluetoothSocketMac::OnRfcommChannelDataReceived( 509 void BluetoothSocketMac::OnChannelDataReceived(
573 IOBluetoothRFCOMMChannel* rfcomm_channel,
574 void* data, 510 void* data,
575 size_t length) { 511 size_t length) {
576 DCHECK(thread_checker_.CalledOnValidThread()); 512 DCHECK(thread_checker_.CalledOnValidThread());
577 DCHECK_EQ(rfcomm_channel_, rfcomm_channel);
578 DCHECK(!is_connecting()); 513 DCHECK(!is_connecting());
579 514
580 int data_size = base::checked_cast<int>(length); 515 int data_size = base::checked_cast<int>(length);
581 scoped_refptr<net::IOBufferWithSize> buffer( 516 scoped_refptr<net::IOBufferWithSize> buffer(
582 new net::IOBufferWithSize(data_size)); 517 new net::IOBufferWithSize(data_size));
583 memcpy(buffer->data(), data, buffer->size()); 518 memcpy(buffer->data(), data, buffer->size());
584 519
585 // If there is a pending read callback, call it now. 520 // If there is a pending read callback, call it now.
586 if (receive_callbacks_) { 521 if (receive_callbacks_) {
587 scoped_ptr<ReceiveCallbacks> temp = receive_callbacks_.Pass(); 522 scoped_ptr<ReceiveCallbacks> temp = receive_callbacks_.Pass();
588 temp->success_callback.Run(buffer->size(), buffer); 523 temp->success_callback.Run(buffer->size(), buffer);
589 return; 524 return;
590 } 525 }
591 526
592 // Otherwise, enqueue the buffer for later use 527 // Otherwise, enqueue the buffer for later use
593 receive_queue_.push(buffer); 528 receive_queue_.push(buffer);
594 } 529 }
595 530
596 void BluetoothSocketMac::Send(scoped_refptr<net::IOBuffer> buffer, 531 void BluetoothSocketMac::Send(scoped_refptr<net::IOBuffer> buffer,
597 int buffer_size, 532 int buffer_size,
598 const SendCompletionCallback& success_callback, 533 const SendCompletionCallback& success_callback,
599 const ErrorCompletionCallback& error_callback) { 534 const ErrorCompletionCallback& error_callback) {
600 DCHECK(thread_checker_.CalledOnValidThread()); 535 DCHECK(thread_checker_.CalledOnValidThread());
601 536
602 if (is_connecting()) { 537 if (is_connecting()) {
603 error_callback.Run(kSocketConnecting); 538 error_callback.Run(kSocketConnecting);
604 return; 539 return;
605 } 540 }
606 541
607 if (!rfcomm_channel_) { 542 if (!channel_) {
608 error_callback.Run(kSocketNotConnected); 543 error_callback.Run(kSocketNotConnected);
609 return; 544 return;
610 } 545 }
611 546
612 // Create and enqueue request in preparation of async writes. 547 // Create and enqueue request in preparation of async writes.
613 linked_ptr<SendRequest> request(new SendRequest()); 548 linked_ptr<SendRequest> request(new SendRequest());
614 request->buffer_size = buffer_size; 549 request->buffer_size = buffer_size;
615 request->success_callback = success_callback; 550 request->success_callback = success_callback;
616 request->error_callback = error_callback; 551 request->error_callback = error_callback;
617 send_queue_.push(request); 552 send_queue_.push(request);
618 553
619 // |writeAsync| accepts buffers of max. mtu bytes per call, so we need to emit 554 // |writeAsync| accepts buffers of max. mtu bytes per call, so we need to emit
620 // multiple write operations if buffer_size > mtu. 555 // multiple write operations if buffer_size > mtu.
621 BluetoothRFCOMMMTU mtu = [rfcomm_channel_ getMTU]; 556 uint16_t mtu = channel_->GetOutgoingMTU();
622 scoped_refptr<net::DrainableIOBuffer> send_buffer( 557 scoped_refptr<net::DrainableIOBuffer> send_buffer(
623 new net::DrainableIOBuffer(buffer, buffer_size)); 558 new net::DrainableIOBuffer(buffer, buffer_size));
624 while (send_buffer->BytesRemaining() > 0) { 559 while (send_buffer->BytesRemaining() > 0) {
625 int byte_count = send_buffer->BytesRemaining(); 560 int byte_count = send_buffer->BytesRemaining();
626 if (byte_count > mtu) 561 if (byte_count > mtu)
627 byte_count = mtu; 562 byte_count = mtu;
628 IOReturn status = [rfcomm_channel_ writeAsync:send_buffer->data() 563 IOReturn status =
629 length:byte_count 564 channel_->WriteAsync(send_buffer->data(), byte_count, request.get());
630 refcon:request.get()]; 565
631 if (status != kIOReturnSuccess) { 566 if (status != kIOReturnSuccess) {
632 std::stringstream error; 567 std::stringstream error;
633 error << "Failed to connect bluetooth socket (" 568 error << "Failed to connect bluetooth socket ("
634 << BluetoothDeviceMac::GetDeviceAddress([rfcomm_channel_ getDevice]) 569 << channel_->GetDeviceAddress() << "): (" << status << ")";
635 << "): (" << status << ")";
636 // Remember the first error only 570 // Remember the first error only
637 if (request->status == kIOReturnSuccess) 571 if (request->status == kIOReturnSuccess)
638 request->status = status; 572 request->status = status;
639 request->error_signaled = true; 573 request->error_signaled = true;
640 request->error_callback.Run(error.str()); 574 request->error_callback.Run(error.str());
641 // We may have failed to issue any write operation. In that case, there 575 // We may have failed to issue any write operation. In that case, there
642 // will be no corresponding completion callback for this particular 576 // will be no corresponding completion callback for this particular
643 // request, so we must forget about it now. 577 // request, so we must forget about it now.
644 if (request->active_async_writes == 0) { 578 if (request->active_async_writes == 0) {
645 send_queue_.pop(); 579 send_queue_.pop();
646 } 580 }
647 return; 581 return;
648 } 582 }
649 583
650 request->active_async_writes++; 584 request->active_async_writes++;
651 send_buffer->DidConsume(byte_count); 585 send_buffer->DidConsume(byte_count);
652 } 586 }
653 } 587 }
654 588
655 void BluetoothSocketMac::OnRfcommChannelWriteComplete( 589 void BluetoothSocketMac::OnChannelWriteComplete(void* refcon, IOReturn status) {
656 IOBluetoothRFCOMMChannel* rfcomm_channel,
657 void* refcon,
658 IOReturn status) {
659 DCHECK(thread_checker_.CalledOnValidThread()); 590 DCHECK(thread_checker_.CalledOnValidThread());
660 591
661 // Note: We use "CHECK" below to ensure we never run into unforeseen 592 // Note: We use "CHECK" below to ensure we never run into unforeseen
662 // occurrences of asynchronous callbacks, which could lead to data 593 // occurrences of asynchronous callbacks, which could lead to data
663 // corruption. 594 // corruption.
664 CHECK_EQ(rfcomm_channel_, rfcomm_channel);
665 CHECK_EQ(static_cast<SendRequest*>(refcon), send_queue_.front().get()); 595 CHECK_EQ(static_cast<SendRequest*>(refcon), send_queue_.front().get());
666 596
667 // Keep a local linked_ptr to avoid releasing the request too early if we end 597 // Keep a local linked_ptr to avoid releasing the request too early if we end
668 // up removing it from the queue. 598 // up removing it from the queue.
669 linked_ptr<SendRequest> request = send_queue_.front(); 599 linked_ptr<SendRequest> request = send_queue_.front();
670 600
671 // Remember the first error only 601 // Remember the first error only
672 if (status != kIOReturnSuccess) { 602 if (status != kIOReturnSuccess) {
673 if (request->status == kIOReturnSuccess) 603 if (request->status == kIOReturnSuccess)
674 request->status = status; 604 request->status = status;
675 } 605 }
676 606
677 // Figure out if we are done with this async request 607 // Figure out if we are done with this async request
678 request->active_async_writes--; 608 request->active_async_writes--;
679 if (request->active_async_writes > 0) 609 if (request->active_async_writes > 0)
680 return; 610 return;
681 611
682 // If this was the last active async write for this request, remove it from 612 // If this was the last active async write for this request, remove it from
683 // the queue and call the appropriate callback associated to the request. 613 // the queue and call the appropriate callback associated to the request.
684 send_queue_.pop(); 614 send_queue_.pop();
685 if (request->status != kIOReturnSuccess) { 615 if (request->status != kIOReturnSuccess) {
686 if (!request->error_signaled) { 616 if (!request->error_signaled) {
687 std::stringstream error; 617 std::stringstream error;
688 error << "Failed to connect bluetooth socket (" 618 error << "Failed to connect bluetooth socket ("
689 << BluetoothDeviceMac::GetDeviceAddress([rfcomm_channel_ getDevice]) 619 << channel_->GetDeviceAddress() << "): (" << status << ")";
690 << "): (" << status << ")";
691 request->error_signaled = true; 620 request->error_signaled = true;
692 request->error_callback.Run(error.str()); 621 request->error_callback.Run(error.str());
693 } 622 }
694 } else { 623 } else {
695 request->success_callback.Run(request->buffer_size); 624 request->success_callback.Run(request->buffer_size);
696 } 625 }
697 } 626 }
698 627
699 void BluetoothSocketMac::OnRfcommChannelClosed( 628 void BluetoothSocketMac::OnChannelClosed() {
700 IOBluetoothRFCOMMChannel* rfcomm_channel) {
701 DCHECK(thread_checker_.CalledOnValidThread()); 629 DCHECK(thread_checker_.CalledOnValidThread());
702 DCHECK_EQ(rfcomm_channel_, rfcomm_channel);
703 630
704 if (receive_callbacks_) { 631 if (receive_callbacks_) {
705 scoped_ptr<ReceiveCallbacks> temp = receive_callbacks_.Pass(); 632 scoped_ptr<ReceiveCallbacks> temp = receive_callbacks_.Pass();
706 temp->error_callback.Run(BluetoothSocket::kDisconnected, 633 temp->error_callback.Run(BluetoothSocket::kDisconnected,
707 kSocketNotConnected); 634 kSocketNotConnected);
708 } 635 }
709 636
710 ReleaseChannel(); 637 ReleaseChannel();
711 } 638 }
712 639
(...skipping 11 matching lines...) Expand all
724 accept_request_.reset(new AcceptRequest); 651 accept_request_.reset(new AcceptRequest);
725 accept_request_->success_callback = success_callback; 652 accept_request_->success_callback = success_callback;
726 accept_request_->error_callback = error_callback; 653 accept_request_->error_callback = error_callback;
727 654
728 if (accept_queue_.size() >= 1) 655 if (accept_queue_.size() >= 1)
729 AcceptConnectionRequest(); 656 AcceptConnectionRequest();
730 } 657 }
731 658
732 void BluetoothSocketMac::AcceptConnectionRequest() { 659 void BluetoothSocketMac::AcceptConnectionRequest() {
733 DCHECK(thread_checker_.CalledOnValidThread()); 660 DCHECK(thread_checker_.CalledOnValidThread());
734 VLOG(1) << uuid_.canonical_value() << ": Accepting pending connection."; 661 DVLOG(1) << uuid_.canonical_value() << ": Accepting pending connection.";
735 662
736 base::scoped_nsobject<IOBluetoothRFCOMMChannel> rfcomm_channel = 663 linked_ptr<BluetoothChannelMac> channel = accept_queue_.front();
737 accept_queue_.front(); 664 accept_queue_.pop();
738 665
739 // TODO(isherman): Is it actually guaranteed that the device is still 666 // TODO(isherman): Is it actually guaranteed that the device is still
740 // connected at this point? 667 // connected at this point?
741 BluetoothDevice* device = adapter_->GetDevice( 668 BluetoothDevice* device = adapter_->GetDevice(channel->GetDeviceAddress());
742 BluetoothDeviceMac::GetDeviceAddress([rfcomm_channel getDevice]));
743 DCHECK(device); 669 DCHECK(device);
744 670
745 scoped_refptr<BluetoothSocketMac> client_socket = 671 scoped_refptr<BluetoothSocketMac> client_socket =
746 BluetoothSocketMac::CreateSocket(); 672 BluetoothSocketMac::CreateSocket();
747 673
748 client_socket->uuid_ = uuid_; 674 client_socket->uuid_ = uuid_;
749 client_socket->rfcomm_channel_.reset([rfcomm_channel retain]); 675 client_socket->channel_.reset(channel.release());
750 client_socket->rfcomm_channel_delegate_.reset(
751 [[BluetoothRfcommChannelDelegate alloc] initWithSocket:client_socket]);
752 676
753 // Setting the delegate will cause the delegate method for open complete 677 // Associating the socket can synchronously call into OnChannelOpenComplete().
754 // to be called on the new socket. Set the new socket to be connecting and 678 // Make sure to first set the new socket to be connecting and hook it up to
755 // hook it up to run the accept callback with the device object. 679 // run the accept callback with the device object.
756 client_socket->connect_callbacks_.reset(new ConnectCallbacks()); 680 client_socket->connect_callbacks_.reset(new ConnectCallbacks());
757 client_socket->connect_callbacks_->success_callback = 681 client_socket->connect_callbacks_->success_callback =
758 base::Bind(accept_request_->success_callback, device, client_socket); 682 base::Bind(accept_request_->success_callback, device, client_socket);
759 client_socket->connect_callbacks_->error_callback = 683 client_socket->connect_callbacks_->error_callback =
760 accept_request_->error_callback; 684 accept_request_->error_callback;
685 accept_request_.reset();
761 686
762 [client_socket->rfcomm_channel_ 687 // Now it's safe to associate the socket with the channel.
763 setDelegate:client_socket->rfcomm_channel_delegate_]; 688 client_socket->channel_->SetSocket(client_socket.get());
764 689
765 accept_request_.reset(); 690 DVLOG(1) << uuid_.canonical_value() << ": Accept complete.";
766 accept_queue_.pop();
767
768 VLOG(1) << uuid_.canonical_value() << ": Accept complete.";
769 } 691 }
770 692
771 BluetoothSocketMac::AcceptRequest::AcceptRequest() {} 693 BluetoothSocketMac::AcceptRequest::AcceptRequest() {}
772 694
773 BluetoothSocketMac::AcceptRequest::~AcceptRequest() {} 695 BluetoothSocketMac::AcceptRequest::~AcceptRequest() {}
774 696
775 BluetoothSocketMac::SendRequest::SendRequest() 697 BluetoothSocketMac::SendRequest::SendRequest()
776 : status(kIOReturnSuccess), active_async_writes(0), error_signaled(false) {} 698 : status(kIOReturnSuccess), active_async_writes(0), error_signaled(false) {}
777 699
778 BluetoothSocketMac::SendRequest::~SendRequest() {} 700 BluetoothSocketMac::SendRequest::~SendRequest() {}
779 701
780 BluetoothSocketMac::ReceiveCallbacks::ReceiveCallbacks() {} 702 BluetoothSocketMac::ReceiveCallbacks::ReceiveCallbacks() {}
781 703
782 BluetoothSocketMac::ReceiveCallbacks::~ReceiveCallbacks() {} 704 BluetoothSocketMac::ReceiveCallbacks::~ReceiveCallbacks() {}
783 705
784 BluetoothSocketMac::ConnectCallbacks::ConnectCallbacks() {} 706 BluetoothSocketMac::ConnectCallbacks::ConnectCallbacks() {}
785 707
786 BluetoothSocketMac::ConnectCallbacks::~ConnectCallbacks() {} 708 BluetoothSocketMac::ConnectCallbacks::~ConnectCallbacks() {}
787 709
788 BluetoothSocketMac::BluetoothSocketMac() 710 BluetoothSocketMac::BluetoothSocketMac()
789 : service_record_handle_(kInvalidServiceRecordHandle) { 711 : service_record_handle_(kInvalidServiceRecordHandle) {
790 } 712 }
791 713
792 BluetoothSocketMac::~BluetoothSocketMac() { 714 BluetoothSocketMac::~BluetoothSocketMac() {
793 DCHECK(thread_checker_.CalledOnValidThread()); 715 DCHECK(thread_checker_.CalledOnValidThread());
794 DCHECK(!rfcomm_channel_); 716 DCHECK(!channel_);
795 DCHECK(!rfcomm_connection_listener_); 717 DCHECK(!rfcomm_connection_listener_);
796 } 718 }
797 719
798 void BluetoothSocketMac::ReleaseChannel() { 720 void BluetoothSocketMac::ReleaseChannel() {
799 DCHECK(thread_checker_.CalledOnValidThread()); 721 DCHECK(thread_checker_.CalledOnValidThread());
800 if (rfcomm_channel_) { 722 channel_.reset();
801 [rfcomm_channel_ setDelegate:nil];
802 [rfcomm_channel_ closeChannel];
803 rfcomm_channel_.reset();
804 rfcomm_channel_delegate_.reset();
805 }
806 723
807 // Closing the channel above prevents the callback delegate from being called 724 // Closing the channel above prevents the callback delegate from being called
808 // so it is now safe to release all callback state. 725 // so it is now safe to release all callback state.
809 connect_callbacks_.reset(); 726 connect_callbacks_.reset();
810 receive_callbacks_.reset(); 727 receive_callbacks_.reset();
811 empty_queue(receive_queue_); 728 empty_queue(receive_queue_);
812 empty_queue(send_queue_); 729 empty_queue(send_queue_);
813 } 730 }
814 731
815 void BluetoothSocketMac::ReleaseListener() { 732 void BluetoothSocketMac::ReleaseListener() {
816 DCHECK(thread_checker_.CalledOnValidThread()); 733 DCHECK(thread_checker_.CalledOnValidThread());
817 DCHECK_NE(service_record_handle_, kInvalidServiceRecordHandle); 734 DCHECK_NE(service_record_handle_, kInvalidServiceRecordHandle);
818 735
819 IOBluetoothRemoveServiceWithRecordHandle(service_record_handle_); 736 IOBluetoothRemoveServiceWithRecordHandle(service_record_handle_);
820 rfcomm_connection_listener_.reset(); 737 rfcomm_connection_listener_.reset();
738
739 // Destroying the listener above prevents the callback delegate from being
740 // called so it is now safe to release all callback state.
741 accept_request_.reset();
742 empty_queue(accept_queue_);
821 } 743 }
822 744
823 } // namespace device 745 } // namespace device
OLDNEW
« no previous file with comments | « device/bluetooth/bluetooth_socket_mac.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698