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