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