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.
5 #include "device/bluetooth/bluetooth_socket_chromeos.h"
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"
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"
40 using device::BluetoothAdapter
;
41 using device::BluetoothDevice
;
42 using device::BluetoothSocketThread
;
43 using device::BluetoothUUID
;
47 const char kAcceptFailed
[] = "Failed to accept connection.";
48 const char kInvalidUUID
[] = "Invalid UUID";
49 const char kSocketNotListening
[] = "Socket is not listening.";
56 scoped_refptr
<BluetoothSocketChromeOS
>
57 BluetoothSocketChromeOS::CreateBluetoothSocket(
58 scoped_refptr
<base::SequencedTaskRunner
> ui_task_runner
,
59 scoped_refptr
<BluetoothSocketThread
> socket_thread
,
61 const net::NetLog::Source
& source
) {
62 DCHECK(ui_task_runner
->RunsTasksOnCurrentThread());
64 return make_scoped_refptr(
65 new BluetoothSocketChromeOS(
66 ui_task_runner
, socket_thread
, net_log
, source
));
69 BluetoothSocketChromeOS::AcceptRequest::AcceptRequest() {}
71 BluetoothSocketChromeOS::AcceptRequest::~AcceptRequest() {}
73 BluetoothSocketChromeOS::ConnectionRequest::ConnectionRequest()
77 BluetoothSocketChromeOS::ConnectionRequest::~ConnectionRequest() {}
79 BluetoothSocketChromeOS::BluetoothSocketChromeOS(
80 scoped_refptr
<base::SequencedTaskRunner
> ui_task_runner
,
81 scoped_refptr
<BluetoothSocketThread
> socket_thread
,
83 const net::NetLog::Source
& source
)
84 : BluetoothSocketNet(ui_task_runner
, socket_thread
, net_log
, source
) {
87 BluetoothSocketChromeOS::~BluetoothSocketChromeOS() {
88 DCHECK(object_path_
.value().empty());
89 DCHECK(profile_
.get() == NULL
);
92 adapter_
->RemoveObserver(this);
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());
106 if (!uuid
.IsValid()) {
107 error_callback
.Run(kInvalidUUID
);
111 device_address_
= device
->GetAddress();
112 device_path_
= device
->object_path();
114 options_
.reset(new BluetoothProfileManagerClient::Options());
116 RegisterProfile(success_callback
, error_callback
);
119 void BluetoothSocketChromeOS::Listen(
120 scoped_refptr
<BluetoothAdapter
> adapter
,
121 SocketType socket_type
,
122 const BluetoothUUID
& uuid
,
125 const base::Closure
& success_callback
,
126 const ErrorCompletionCallback
& error_callback
) {
127 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
128 DCHECK(object_path_
.value().empty());
129 DCHECK(!profile_
.get());
131 if (!uuid
.IsValid()) {
132 error_callback
.Run(kInvalidUUID
);
137 adapter_
->AddObserver(this);
140 options_
.reset(new BluetoothProfileManagerClient::Options());
142 switch (socket_type
) {
144 options_
->channel
.reset(new uint16(
145 psm_or_channel
== BluetoothAdapter::kChannelAuto
146 ? 0 : psm_or_channel
));
149 options_
->psm
.reset(new uint16(
150 psm_or_channel
== BluetoothAdapter::kPsmAuto
151 ? 0 : psm_or_channel
));
158 options_
->require_authentication
.reset(new bool(false));
160 RegisterProfile(success_callback
, error_callback
);
163 void BluetoothSocketChromeOS::Close() {
164 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
169 if (!device_path_
.value().empty()) {
170 BluetoothSocketNet::Close();
176 void BluetoothSocketChromeOS::Disconnect(const base::Closure
& callback
) {
177 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
182 if (!device_path_
.value().empty()) {
183 BluetoothSocketNet::Disconnect(callback
);
190 void BluetoothSocketChromeOS::Accept(
191 const AcceptCompletionCallback
& success_callback
,
192 const ErrorCompletionCallback
& error_callback
) {
193 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
195 if (!device_path_
.value().empty()) {
196 error_callback
.Run(kSocketNotListening
);
200 // Only one pending accept at a time
201 if (accept_request_
.get()) {
202 error_callback
.Run(net::ErrorToString(net::ERR_IO_PENDING
));
206 accept_request_
.reset(new AcceptRequest
);
207 accept_request_
->success_callback
= success_callback
;
208 accept_request_
->error_callback
= error_callback
;
210 if (connection_request_queue_
.size() >= 1) {
211 AcceptConnectionRequest();
215 void BluetoothSocketChromeOS::RegisterProfile(
216 const base::Closure
& success_callback
,
217 const ErrorCompletionCallback
& error_callback
) {
218 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
219 DCHECK(object_path_
.value().empty());
220 DCHECK(!profile_
.get());
222 // The object path is relatively meaningless, but has to be unique, so for
223 // connecting profiles use a combination of the device address and profile
225 std::string device_address_path
, uuid_path
;
226 base::ReplaceChars(device_address_
, ":-", "_", &device_address_path
);
227 base::ReplaceChars(uuid_
.canonical_value(), ":-", "_", &uuid_path
);
228 if (!device_address_path
.empty()) {
229 object_path_
= dbus::ObjectPath("/org/chromium/bluetooth_profile/" +
230 device_address_path
+ "/" + uuid_path
);
232 object_path_
= dbus::ObjectPath("/org/chromium/bluetooth_profile/" +
236 // Create the service provider for the profile object.
237 dbus::Bus
* system_bus
= DBusThreadManager::Get()->GetSystemBus();
238 profile_
.reset(BluetoothProfileServiceProvider::Create(
239 system_bus
, object_path_
, this));
240 DCHECK(profile_
.get());
242 // Before reaching out to the Bluetooth Daemon to register a listening socket,
243 // make sure it's actually running. If not, report success and carry on;
244 // the profile will be registered when the daemon becomes available.
245 if (adapter_
&& !adapter_
->IsPresent()) {
246 VLOG(1) << object_path_
.value() << ": Delaying profile registration.";
247 success_callback
.Run();
251 VLOG(1) << object_path_
.value() << ": Registering profile.";
252 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
255 uuid_
.canonical_value(),
257 base::Bind(&BluetoothSocketChromeOS::OnRegisterProfile
,
261 base::Bind(&BluetoothSocketChromeOS::OnRegisterProfileError
,
266 void BluetoothSocketChromeOS::OnRegisterProfile(
267 const base::Closure
& success_callback
,
268 const ErrorCompletionCallback
& error_callback
) {
269 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
270 if (!device_path_
.value().empty()) {
271 VLOG(1) << object_path_
.value() << ": Profile registered, connecting to "
272 << device_path_
.value();
274 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
277 uuid_
.canonical_value(),
279 &BluetoothSocketChromeOS::OnConnectProfile
,
283 &BluetoothSocketChromeOS::OnConnectProfileError
,
287 VLOG(1) << object_path_
.value() << ": Profile registered.";
288 success_callback
.Run();
292 void BluetoothSocketChromeOS::OnRegisterProfileError(
293 const ErrorCompletionCallback
& error_callback
,
294 const std::string
& error_name
,
295 const std::string
& error_message
) {
296 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
297 LOG(WARNING
) << object_path_
.value() << ": Failed to register profile: "
298 << error_name
<< ": " << error_message
;
299 error_callback
.Run(error_message
);
302 void BluetoothSocketChromeOS::OnConnectProfile(
303 const base::Closure
& success_callback
) {
304 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
305 VLOG(1) << object_path_
.value() << ": Profile connected.";
307 success_callback
.Run();
310 void BluetoothSocketChromeOS::OnConnectProfileError(
311 const ErrorCompletionCallback
& error_callback
,
312 const std::string
& error_name
,
313 const std::string
& error_message
) {
314 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
315 LOG(WARNING
) << object_path_
.value() << ": Failed to connect profile: "
316 << error_name
<< ": " << error_message
;
318 error_callback
.Run(error_message
);
321 void BluetoothSocketChromeOS::AdapterPresentChanged(BluetoothAdapter
* adapter
,
323 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
324 DCHECK(!object_path_
.value().empty());
325 DCHECK(profile_
.get());
330 VLOG(1) << object_path_
.value() << ": Re-register profile.";
331 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
334 uuid_
.canonical_value(),
336 base::Bind(&BluetoothSocketChromeOS::OnInternalRegisterProfile
,
338 base::Bind(&BluetoothSocketChromeOS::OnInternalRegisterProfileError
,
342 void BluetoothSocketChromeOS::OnInternalRegisterProfile() {
343 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
345 VLOG(1) << object_path_
.value() << ": Profile re-registered";
348 void BluetoothSocketChromeOS::OnInternalRegisterProfileError(
349 const std::string
& error_name
,
350 const std::string
& error_message
) {
351 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
353 // It's okay if the profile already exists, it means we registered it on
355 if (error_name
== bluetooth_profile_manager::kErrorAlreadyExists
)
358 LOG(WARNING
) << object_path_
.value() << ": Failed to re-register profile: "
359 << error_name
<< ": " << error_message
;
362 void BluetoothSocketChromeOS::Released() {
363 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
364 VLOG(1) << object_path_
.value() << ": Release";
367 void BluetoothSocketChromeOS::NewConnection(
368 const dbus::ObjectPath
& device_path
,
369 scoped_ptr
<dbus::FileDescriptor
> fd
,
370 const BluetoothProfileServiceProvider::Delegate::Options
& options
,
371 const ConfirmationCallback
& callback
) {
372 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
373 VLOG(1) << object_path_
.value() << ": New connection from device: "
374 << device_path
.value();
376 if (!device_path_
.value().empty()) {
377 DCHECK(device_path_
== device_path
);
379 socket_thread()->task_runner()->PostTask(
382 &BluetoothSocketChromeOS::DoNewConnection
,
389 linked_ptr
<ConnectionRequest
> request(new ConnectionRequest());
390 request
->device_path
= device_path
;
391 request
->fd
= fd
.Pass();
392 request
->options
= options
;
393 request
->callback
= callback
;
395 connection_request_queue_
.push(request
);
396 VLOG(1) << object_path_
.value() << ": Connection is now pending.";
397 if (accept_request_
) {
398 AcceptConnectionRequest();
403 void BluetoothSocketChromeOS::RequestDisconnection(
404 const dbus::ObjectPath
& device_path
,
405 const ConfirmationCallback
& callback
) {
406 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
407 VLOG(1) << object_path_
.value() << ": Request disconnection";
408 callback
.Run(SUCCESS
);
411 void BluetoothSocketChromeOS::Cancel() {
412 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
413 VLOG(1) << object_path_
.value() << ": Cancel";
415 if (!connection_request_queue_
.size())
418 // If the front request is being accepted mark it as cancelled, otherwise
419 // just pop it from the queue.
420 linked_ptr
<ConnectionRequest
> request
= connection_request_queue_
.front();
421 if (!request
->accepting
) {
422 request
->cancelled
= true;
424 connection_request_queue_
.pop();
428 void BluetoothSocketChromeOS::AcceptConnectionRequest() {
429 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
430 DCHECK(accept_request_
.get());
431 DCHECK(connection_request_queue_
.size() >= 1);
433 VLOG(1) << object_path_
.value() << ": Accepting pending connection.";
435 linked_ptr
<ConnectionRequest
> request
= connection_request_queue_
.front();
436 request
->accepting
= true;
438 BluetoothDeviceChromeOS
* device
=
439 static_cast<BluetoothAdapterChromeOS
*>(adapter_
.get())->
440 GetDeviceWithPath(request
->device_path
);
443 scoped_refptr
<BluetoothSocketChromeOS
> client_socket
=
444 BluetoothSocketChromeOS::CreateBluetoothSocket(
450 client_socket
->device_address_
= device
->GetAddress();
451 client_socket
->device_path_
= request
->device_path
;
452 client_socket
->uuid_
= uuid_
;
454 socket_thread()->task_runner()->PostTask(
457 &BluetoothSocketChromeOS::DoNewConnection
,
459 request
->device_path
,
460 base::Passed(&request
->fd
),
462 base::Bind(&BluetoothSocketChromeOS::OnNewConnection
,
465 request
->callback
)));
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();
477 VLOG(1) << object_path_
.value() << ": Validity check complete.";
478 if (!fd
->is_valid()) {
479 ui_task_runner()->PostTask(FROM_HERE
,
480 base::Bind(callback
, REJECTED
));;
485 LOG(WARNING
) << object_path_
.value() << ": Already connected";
486 ui_task_runner()->PostTask(FROM_HERE
,
487 base::Bind(callback
, REJECTED
));;
493 // Note: We don't have a meaningful |IPEndPoint|, but that is ok since the
494 // TCPSocket implementation does not actually require one.
495 int net_result
= tcp_socket()->AdoptConnectedSocket(fd
->value(),
497 if (net_result
!= net::OK
) {
498 LOG(WARNING
) << object_path_
.value() << ": Error adopting socket: "
499 << std::string(net::ErrorToString(net_result
));
500 ui_task_runner()->PostTask(FROM_HERE
,
501 base::Bind(callback
, REJECTED
));;
506 ui_task_runner()->PostTask(FROM_HERE
,
507 base::Bind(callback
, SUCCESS
));;
510 void BluetoothSocketChromeOS::OnNewConnection(
511 scoped_refptr
<BluetoothSocket
> socket
,
512 const ConfirmationCallback
& callback
,
514 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
515 DCHECK(accept_request_
.get());
516 DCHECK(connection_request_queue_
.size() >= 1);
518 linked_ptr
<ConnectionRequest
> request
= connection_request_queue_
.front();
519 if (status
== SUCCESS
&& !request
->cancelled
) {
520 BluetoothDeviceChromeOS
* device
=
521 static_cast<BluetoothAdapterChromeOS
*>(adapter_
.get())->
522 GetDeviceWithPath(request
->device_path
);
525 accept_request_
->success_callback
.Run(device
, socket
);
527 accept_request_
->error_callback
.Run(kAcceptFailed
);
530 accept_request_
.reset(NULL
);
531 connection_request_queue_
.pop();
533 callback
.Run(status
);
536 void BluetoothSocketChromeOS::DoCloseListening() {
537 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
539 if (accept_request_
) {
540 accept_request_
->error_callback
.Run(
541 net::ErrorToString(net::ERR_CONNECTION_CLOSED
));
542 accept_request_
.reset(NULL
);
545 while (connection_request_queue_
.size() > 0) {
546 linked_ptr
<ConnectionRequest
> request
= connection_request_queue_
.front();
547 request
->callback
.Run(REJECTED
);
548 connection_request_queue_
.pop();
552 void BluetoothSocketChromeOS::UnregisterProfile() {
553 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
554 DCHECK(!object_path_
.value().empty());
555 DCHECK(profile_
.get());
557 VLOG(1) << object_path_
.value() << ": Unregister profile";
558 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
561 base::Bind(&BluetoothSocketChromeOS::OnUnregisterProfile
,
564 base::Bind(&BluetoothSocketChromeOS::OnUnregisterProfileError
,
569 object_path_
= dbus::ObjectPath("");
572 void BluetoothSocketChromeOS::OnUnregisterProfile(
573 const dbus::ObjectPath
& object_path
) {
574 VLOG(1) << object_path
.value() << ": Profile unregistered";
577 void BluetoothSocketChromeOS::OnUnregisterProfileError(
578 const dbus::ObjectPath
& object_path
,
579 const std::string
& error_name
,
580 const std::string
& error_message
) {
581 // It's okay if the profile doesn't exist, it means we haven't registered it
583 if (error_name
== bluetooth_profile_manager::kErrorDoesNotExist
)
586 LOG(WARNING
) << object_path_
.value() << ": Failed to unregister profile: "
587 << error_name
<< ": " << error_message
;
590 } // namespace chromeos