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