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 3 // found in the LICENSE file. 4 5 #include "device/bluetooth/bluetooth_socket_chromeos.h" 6 7 #include <queue> 8 #include <string> 9 10 #include "base/basictypes.h" 11 #include "base/bind.h" 12 #include "base/callback.h" 13 #include "base/logging.h" 14 #include "base/memory/linked_ptr.h" 15 #include "base/memory/ref_counted.h" 16 #include "base/memory/scoped_ptr.h" 17 #include "base/sequenced_task_runner.h" 18 #include "base/strings/string_util.h" 19 #include "base/task_runner_util.h" 20 #include "base/threading/thread_restrictions.h" 21 #include "base/threading/worker_pool.h" 22 #include "chromeos/dbus/bluetooth_device_client.h" 23 #include "chromeos/dbus/bluetooth_profile_manager_client.h" 24 #include "chromeos/dbus/bluetooth_profile_service_provider.h" 25 #include "chromeos/dbus/dbus_thread_manager.h" 26 #include "dbus/bus.h" 27 #include "dbus/file_descriptor.h" 28 #include "dbus/object_path.h" 29 #include "device/bluetooth/bluetooth_adapter.h" 30 #include "device/bluetooth/bluetooth_adapter_chromeos.h" 31 #include "device/bluetooth/bluetooth_device.h" 32 #include "device/bluetooth/bluetooth_device_chromeos.h" 33 #include "device/bluetooth/bluetooth_socket.h" 34 #include "device/bluetooth/bluetooth_socket_net.h" 35 #include "device/bluetooth/bluetooth_socket_thread.h" 36 #include "net/base/ip_endpoint.h" 37 #include "net/base/net_errors.h" 38 #include "third_party/cros_system_api/dbus/service_constants.h" 39 40 using device::BluetoothAdapter; 41 using device::BluetoothDevice; 42 using device::BluetoothSocketThread; 43 using device::BluetoothUUID; 44 45 namespace { 46 47 const char kAcceptFailed[] = "Failed to accept connection."; 48 const char kInvalidUUID[] = "Invalid UUID"; 49 const char kSocketNotListening[] = "Socket is not listening."; 50 51 } // namespace 52 53 namespace chromeos { 54 55 // static 56 scoped_refptr<BluetoothSocketChromeOS> 57 BluetoothSocketChromeOS::CreateBluetoothSocket( 58 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, 59 scoped_refptr<BluetoothSocketThread> socket_thread) { 60 DCHECK(ui_task_runner->RunsTasksOnCurrentThread()); 61 62 return make_scoped_refptr( 63 new BluetoothSocketChromeOS(ui_task_runner, socket_thread)); 64 } 65 66 BluetoothSocketChromeOS::AcceptRequest::AcceptRequest() {} 67 68 BluetoothSocketChromeOS::AcceptRequest::~AcceptRequest() {} 69 70 BluetoothSocketChromeOS::ConnectionRequest::ConnectionRequest() 71 : accepting(false), 72 cancelled(false) {} 73 74 BluetoothSocketChromeOS::ConnectionRequest::~ConnectionRequest() {} 75 76 BluetoothSocketChromeOS::BluetoothSocketChromeOS( 77 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, 78 scoped_refptr<BluetoothSocketThread> socket_thread) 79 : BluetoothSocketNet(ui_task_runner, socket_thread) { 80 } 81 82 BluetoothSocketChromeOS::~BluetoothSocketChromeOS() { 83 DCHECK(object_path_.value().empty()); 84 DCHECK(profile_.get() == NULL); 85 86 if (adapter_.get()) { 87 adapter_->RemoveObserver(this); 88 adapter_ = NULL; 89 } 90 } 91 92 void BluetoothSocketChromeOS::Connect( 93 const BluetoothDeviceChromeOS* device, 94 const BluetoothUUID& uuid, 95 SecurityLevel security_level, 96 const base::Closure& success_callback, 97 const ErrorCompletionCallback& error_callback) { 98 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 99 DCHECK(object_path_.value().empty()); 100 DCHECK(!profile_.get()); 101 102 if (!uuid.IsValid()) { 103 error_callback.Run(kInvalidUUID); 104 return; 105 } 106 107 device_address_ = device->GetAddress(); 108 device_path_ = device->object_path(); 109 uuid_ = uuid; 110 options_.reset(new BluetoothProfileManagerClient::Options()); 111 if (security_level == SECURITY_LEVEL_LOW) 112 options_->require_authentication.reset(new bool(false)); 113 114 RegisterProfile(success_callback, error_callback); 115 } 116 117 void BluetoothSocketChromeOS::Listen( 118 scoped_refptr<BluetoothAdapter> adapter, 119 SocketType socket_type, 120 const BluetoothUUID& uuid, 121 const BluetoothAdapter::ServiceOptions& service_options, 122 const base::Closure& success_callback, 123 const ErrorCompletionCallback& error_callback) { 124 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 125 DCHECK(object_path_.value().empty()); 126 DCHECK(!profile_.get()); 127 128 if (!uuid.IsValid()) { 129 error_callback.Run(kInvalidUUID); 130 return; 131 } 132 133 adapter_ = adapter; 134 adapter_->AddObserver(this); 135 136 uuid_ = uuid; 137 options_.reset(new BluetoothProfileManagerClient::Options()); 138 if (service_options.name) 139 options_->name.reset(new std::string(*service_options.name)); 140 141 switch (socket_type) { 142 case kRfcomm: 143 options_->channel.reset( 144 new uint16(service_options.channel ? *service_options.channel : 0)); 145 break; 146 case kL2cap: 147 options_->psm.reset( 148 new uint16(service_options.psm ? *service_options.psm : 0)); 149 break; 150 default: 151 NOTREACHED(); 152 } 153 154 RegisterProfile(success_callback, error_callback); 155 } 156 157 void BluetoothSocketChromeOS::Close() { 158 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 159 160 if (profile_) 161 UnregisterProfile(); 162 163 // In the case below, where an asynchronous task gets posted on the socket 164 // thread in BluetoothSocketNet::Close, a reference will be held to this 165 // socket by the callback. This may cause the BluetoothAdapter to outlive 166 // DBusThreadManager during shutdown if that callback executes too late. 167 if (adapter_.get()) { 168 adapter_->RemoveObserver(this); 169 adapter_ = NULL; 170 } 171 172 if (!device_path_.value().empty()) { 173 BluetoothSocketNet::Close(); 174 } else { 175 DoCloseListening(); 176 } 177 } 178 179 void BluetoothSocketChromeOS::Disconnect(const base::Closure& callback) { 180 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 181 182 if (profile_) 183 UnregisterProfile(); 184 185 if (!device_path_.value().empty()) { 186 BluetoothSocketNet::Disconnect(callback); 187 } else { 188 DoCloseListening(); 189 callback.Run(); 190 } 191 } 192 193 void BluetoothSocketChromeOS::Accept( 194 const AcceptCompletionCallback& success_callback, 195 const ErrorCompletionCallback& error_callback) { 196 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 197 198 if (!device_path_.value().empty()) { 199 error_callback.Run(kSocketNotListening); 200 return; 201 } 202 203 // Only one pending accept at a time 204 if (accept_request_.get()) { 205 error_callback.Run(net::ErrorToString(net::ERR_IO_PENDING)); 206 return; 207 } 208 209 accept_request_.reset(new AcceptRequest); 210 accept_request_->success_callback = success_callback; 211 accept_request_->error_callback = error_callback; 212 213 if (connection_request_queue_.size() >= 1) { 214 AcceptConnectionRequest(); 215 } 216 } 217 218 void BluetoothSocketChromeOS::RegisterProfile( 219 const base::Closure& success_callback, 220 const ErrorCompletionCallback& error_callback) { 221 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 222 DCHECK(object_path_.value().empty()); 223 DCHECK(!profile_.get()); 224 225 // The object path is relatively meaningless, but has to be unique, so for 226 // connecting profiles use a combination of the device address and profile 227 // UUID. 228 std::string device_address_path, uuid_path; 229 base::ReplaceChars(device_address_, ":-", "_", &device_address_path); 230 base::ReplaceChars(uuid_.canonical_value(), ":-", "_", &uuid_path); 231 if (!device_address_path.empty()) { 232 object_path_ = dbus::ObjectPath("/org/chromium/bluetooth_profile/" + 233 device_address_path + "/" + uuid_path); 234 } else { 235 object_path_ = dbus::ObjectPath("/org/chromium/bluetooth_profile/" + 236 uuid_path); 237 } 238 239 // Create the service provider for the profile object. 240 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus(); 241 profile_.reset(BluetoothProfileServiceProvider::Create( 242 system_bus, object_path_, this)); 243 DCHECK(profile_.get()); 244 245 // Before reaching out to the Bluetooth Daemon to register a listening socket, 246 // make sure it's actually running. If not, report success and carry on; 247 // the profile will be registered when the daemon becomes available. 248 if (adapter_.get() && !adapter_->IsPresent()) { 249 VLOG(1) << object_path_.value() << ": Delaying profile registration."; 250 success_callback.Run(); 251 return; 252 } 253 254 VLOG(1) << object_path_.value() << ": Registering profile."; 255 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()-> 256 RegisterProfile( 257 object_path_, 258 uuid_.canonical_value(), 259 *options_, 260 base::Bind(&BluetoothSocketChromeOS::OnRegisterProfile, 261 this, 262 success_callback, 263 error_callback), 264 base::Bind(&BluetoothSocketChromeOS::OnRegisterProfileError, 265 this, 266 error_callback)); 267 } 268 269 void BluetoothSocketChromeOS::OnRegisterProfile( 270 const base::Closure& success_callback, 271 const ErrorCompletionCallback& error_callback) { 272 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 273 if (!device_path_.value().empty()) { 274 VLOG(1) << object_path_.value() << ": Profile registered, connecting to " 275 << device_path_.value(); 276 277 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 278 ConnectProfile( 279 device_path_, 280 uuid_.canonical_value(), 281 base::Bind( 282 &BluetoothSocketChromeOS::OnConnectProfile, 283 this, 284 success_callback), 285 base::Bind( 286 &BluetoothSocketChromeOS::OnConnectProfileError, 287 this, 288 error_callback)); 289 } else { 290 VLOG(1) << object_path_.value() << ": Profile registered."; 291 success_callback.Run(); 292 } 293 } 294 295 void BluetoothSocketChromeOS::OnRegisterProfileError( 296 const ErrorCompletionCallback& error_callback, 297 const std::string& error_name, 298 const std::string& error_message) { 299 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 300 LOG(WARNING) << object_path_.value() << ": Failed to register profile: " 301 << error_name << ": " << error_message; 302 error_callback.Run(error_message); 303 } 304 305 void BluetoothSocketChromeOS::OnConnectProfile( 306 const base::Closure& success_callback) { 307 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 308 VLOG(1) << object_path_.value() << ": Profile connected."; 309 UnregisterProfile(); 310 success_callback.Run(); 311 } 312 313 void BluetoothSocketChromeOS::OnConnectProfileError( 314 const ErrorCompletionCallback& error_callback, 315 const std::string& error_name, 316 const std::string& error_message) { 317 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 318 LOG(WARNING) << object_path_.value() << ": Failed to connect profile: " 319 << error_name << ": " << error_message; 320 UnregisterProfile(); 321 error_callback.Run(error_message); 322 } 323 324 void BluetoothSocketChromeOS::AdapterPresentChanged(BluetoothAdapter* adapter, 325 bool present) { 326 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 327 DCHECK(!object_path_.value().empty()); 328 DCHECK(profile_.get()); 329 330 if (!present) 331 return; 332 333 VLOG(1) << object_path_.value() << ": Re-register profile."; 334 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()-> 335 RegisterProfile( 336 object_path_, 337 uuid_.canonical_value(), 338 *options_, 339 base::Bind(&BluetoothSocketChromeOS::OnInternalRegisterProfile, 340 this), 341 base::Bind(&BluetoothSocketChromeOS::OnInternalRegisterProfileError, 342 this)); 343 } 344 345 void BluetoothSocketChromeOS::OnInternalRegisterProfile() { 346 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 347 348 VLOG(1) << object_path_.value() << ": Profile re-registered"; 349 } 350 351 void BluetoothSocketChromeOS::OnInternalRegisterProfileError( 352 const std::string& error_name, 353 const std::string& error_message) { 354 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 355 356 // It's okay if the profile already exists, it means we registered it on 357 // initialization. 358 if (error_name == bluetooth_profile_manager::kErrorAlreadyExists) 359 return; 360 361 LOG(WARNING) << object_path_.value() << ": Failed to re-register profile: " 362 << error_name << ": " << error_message; 363 } 364 365 void BluetoothSocketChromeOS::Released() { 366 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 367 VLOG(1) << object_path_.value() << ": Release"; 368 } 369 370 void BluetoothSocketChromeOS::NewConnection( 371 const dbus::ObjectPath& device_path, 372 scoped_ptr<dbus::FileDescriptor> fd, 373 const BluetoothProfileServiceProvider::Delegate::Options& options, 374 const ConfirmationCallback& callback) { 375 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 376 VLOG(1) << object_path_.value() << ": New connection from device: " 377 << device_path.value(); 378 379 if (!device_path_.value().empty()) { 380 DCHECK(device_path_ == device_path); 381 382 socket_thread()->task_runner()->PostTask( 383 FROM_HERE, 384 base::Bind( 385 &BluetoothSocketChromeOS::DoNewConnection, 386 this, 387 device_path_, 388 base::Passed(&fd), 389 options, 390 callback)); 391 } else { 392 linked_ptr<ConnectionRequest> request(new ConnectionRequest()); 393 request->device_path = device_path; 394 request->fd = fd.Pass(); 395 request->options = options; 396 request->callback = callback; 397 398 connection_request_queue_.push(request); 399 VLOG(1) << object_path_.value() << ": Connection is now pending."; 400 if (accept_request_) { 401 AcceptConnectionRequest(); 402 } 403 } 404 } 405 406 void BluetoothSocketChromeOS::RequestDisconnection( 407 const dbus::ObjectPath& device_path, 408 const ConfirmationCallback& callback) { 409 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 410 VLOG(1) << object_path_.value() << ": Request disconnection"; 411 callback.Run(SUCCESS); 412 } 413 414 void BluetoothSocketChromeOS::Cancel() { 415 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 416 VLOG(1) << object_path_.value() << ": Cancel"; 417 418 if (!connection_request_queue_.size()) 419 return; 420 421 // If the front request is being accepted mark it as cancelled, otherwise 422 // just pop it from the queue. 423 linked_ptr<ConnectionRequest> request = connection_request_queue_.front(); 424 if (!request->accepting) { 425 request->cancelled = true; 426 } else { 427 connection_request_queue_.pop(); 428 } 429 } 430 431 void BluetoothSocketChromeOS::AcceptConnectionRequest() { 432 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 433 DCHECK(accept_request_.get()); 434 DCHECK(connection_request_queue_.size() >= 1); 435 436 VLOG(1) << object_path_.value() << ": Accepting pending connection."; 437 438 linked_ptr<ConnectionRequest> request = connection_request_queue_.front(); 439 request->accepting = true; 440 441 BluetoothDeviceChromeOS* device = 442 static_cast<BluetoothAdapterChromeOS*>(adapter_.get())-> 443 GetDeviceWithPath(request->device_path); 444 DCHECK(device); 445 446 scoped_refptr<BluetoothSocketChromeOS> client_socket = 447 BluetoothSocketChromeOS::CreateBluetoothSocket( 448 ui_task_runner(), socket_thread()); 449 450 client_socket->device_address_ = device->GetAddress(); 451 client_socket->device_path_ = request->device_path; 452 client_socket->uuid_ = uuid_; 453 454 socket_thread()->task_runner()->PostTask( 455 FROM_HERE, 456 base::Bind( 457 &BluetoothSocketChromeOS::DoNewConnection, 458 client_socket, 459 request->device_path, 460 base::Passed(&request->fd), 461 request->options, 462 base::Bind(&BluetoothSocketChromeOS::OnNewConnection, 463 this, 464 client_socket, 465 request->callback))); 466 } 467 468 void BluetoothSocketChromeOS::DoNewConnection( 469 const dbus::ObjectPath& device_path, 470 scoped_ptr<dbus::FileDescriptor> fd, 471 const BluetoothProfileServiceProvider::Delegate::Options& options, 472 const ConfirmationCallback& callback) { 473 DCHECK(socket_thread()->task_runner()->RunsTasksOnCurrentThread()); 474 base::ThreadRestrictions::AssertIOAllowed(); 475 fd->CheckValidity(); 476 477 VLOG(1) << object_path_.value() << ": Validity check complete."; 478 if (!fd->is_valid()) { 479 LOG(WARNING) << object_path_.value() << " :" << fd->value() 480 << ": Invalid file descriptor received from Bluetooth Daemon."; 481 ui_task_runner()->PostTask(FROM_HERE, 482 base::Bind(callback, REJECTED));; 483 return; 484 } 485 486 if (tcp_socket()) { 487 LOG(WARNING) << object_path_.value() << ": Already connected"; 488 ui_task_runner()->PostTask(FROM_HERE, 489 base::Bind(callback, REJECTED));; 490 return; 491 } 492 493 ResetTCPSocket(); 494 495 // Note: We don't have a meaningful |IPEndPoint|, but that is ok since the 496 // TCPSocket implementation does not actually require one. 497 int net_result = tcp_socket()->AdoptConnectedSocket(fd->value(), 498 net::IPEndPoint()); 499 if (net_result != net::OK) { 500 LOG(WARNING) << object_path_.value() << ": Error adopting socket: " 501 << std::string(net::ErrorToString(net_result)); 502 ui_task_runner()->PostTask(FROM_HERE, 503 base::Bind(callback, REJECTED));; 504 return; 505 } 506 507 VLOG(2) << object_path_.value() << ": Taking descriptor, confirming success."; 508 fd->TakeValue(); 509 ui_task_runner()->PostTask(FROM_HERE, 510 base::Bind(callback, SUCCESS));; 511 } 512 513 void BluetoothSocketChromeOS::OnNewConnection( 514 scoped_refptr<BluetoothSocket> socket, 515 const ConfirmationCallback& callback, 516 Status status) { 517 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 518 DCHECK(accept_request_.get()); 519 DCHECK(connection_request_queue_.size() >= 1); 520 521 linked_ptr<ConnectionRequest> request = connection_request_queue_.front(); 522 if (status == SUCCESS && !request->cancelled) { 523 BluetoothDeviceChromeOS* device = 524 static_cast<BluetoothAdapterChromeOS*>(adapter_.get())-> 525 GetDeviceWithPath(request->device_path); 526 DCHECK(device); 527 528 accept_request_->success_callback.Run(device, socket); 529 } else { 530 accept_request_->error_callback.Run(kAcceptFailed); 531 } 532 533 accept_request_.reset(NULL); 534 connection_request_queue_.pop(); 535 536 callback.Run(status); 537 } 538 539 void BluetoothSocketChromeOS::DoCloseListening() { 540 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 541 542 if (accept_request_) { 543 accept_request_->error_callback.Run( 544 net::ErrorToString(net::ERR_CONNECTION_CLOSED)); 545 accept_request_.reset(NULL); 546 } 547 548 while (connection_request_queue_.size() > 0) { 549 linked_ptr<ConnectionRequest> request = connection_request_queue_.front(); 550 request->callback.Run(REJECTED); 551 connection_request_queue_.pop(); 552 } 553 } 554 555 void BluetoothSocketChromeOS::UnregisterProfile() { 556 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread()); 557 DCHECK(!object_path_.value().empty()); 558 DCHECK(profile_.get()); 559 560 VLOG(1) << object_path_.value() << ": Unregister profile"; 561 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()-> 562 UnregisterProfile( 563 object_path_, 564 base::Bind(&BluetoothSocketChromeOS::OnUnregisterProfile, 565 this, 566 object_path_), 567 base::Bind(&BluetoothSocketChromeOS::OnUnregisterProfileError, 568 this, 569 object_path_)); 570 571 profile_.reset(); 572 object_path_ = dbus::ObjectPath(""); 573 } 574 575 void BluetoothSocketChromeOS::OnUnregisterProfile( 576 const dbus::ObjectPath& object_path) { 577 VLOG(1) << object_path.value() << ": Profile unregistered"; 578 } 579 580 void BluetoothSocketChromeOS::OnUnregisterProfileError( 581 const dbus::ObjectPath& object_path, 582 const std::string& error_name, 583 const std::string& error_message) { 584 // It's okay if the profile doesn't exist, it means we haven't registered it 585 // yet. 586 if (error_name == bluetooth_profile_manager::kErrorDoesNotExist) 587 return; 588 589 LOG(WARNING) << object_path_.value() << ": Failed to unregister profile: " 590 << error_name << ": " << error_message; 591 } 592 593 } // namespace chromeos 594