Turning in DCHECK to test for illegal visibility / opacity flag combination
[chromium-blink-merge.git] / device / bluetooth / bluetooth_socket_chromeos.cc
blobbf0efa0eb82224e6d8c2cf416730681ed647e6a5
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"
7 #include <queue>
8 #include <string>
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"
40 using device::BluetoothAdapter;
41 using device::BluetoothDevice;
42 using device::BluetoothSocketThread;
43 using device::BluetoothUUID;
45 namespace {
47 const char kAcceptFailed[] = "Failed to accept connection.";
48 const char kInvalidUUID[] = "Invalid UUID";
49 const char kSocketNotListening[] = "Socket is not listening.";
51 } // namespace
53 namespace chromeos {
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());
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()
74 : accepting(false),
75 cancelled(false) {}
77 BluetoothSocketChromeOS::ConnectionRequest::~ConnectionRequest() {}
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) {
87 BluetoothSocketChromeOS::~BluetoothSocketChromeOS() {
88 DCHECK(object_path_.value().empty());
89 DCHECK(profile_.get() == NULL);
91 if (adapter_.get()) {
92 adapter_->RemoveObserver(this);
93 adapter_ = NULL;
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);
108 return;
111 device_address_ = device->GetAddress();
112 device_path_ = device->object_path();
113 uuid_ = uuid;
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,
123 int psm_or_channel,
124 bool insecure,
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);
133 return;
136 adapter_ = adapter;
137 adapter_->AddObserver(this);
139 uuid_ = uuid;
140 options_.reset(new BluetoothProfileManagerClient::Options());
142 switch (socket_type) {
143 case kRfcomm:
144 options_->channel.reset(new uint16(
145 psm_or_channel == BluetoothAdapter::kChannelAuto
146 ? 0 : psm_or_channel));
147 break;
148 case kL2cap:
149 options_->psm.reset(new uint16(
150 psm_or_channel == BluetoothAdapter::kPsmAuto
151 ? 0 : psm_or_channel));
152 break;
153 default:
154 NOTREACHED();
157 if (insecure)
158 options_->require_authentication.reset(new bool(false));
160 RegisterProfile(success_callback, error_callback);
163 void BluetoothSocketChromeOS::Close() {
164 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
166 if (profile_)
167 UnregisterProfile();
169 if (!device_path_.value().empty()) {
170 BluetoothSocketNet::Close();
171 } else {
172 DoCloseListening();
176 void BluetoothSocketChromeOS::Disconnect(const base::Closure& callback) {
177 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
179 if (profile_)
180 UnregisterProfile();
182 if (!device_path_.value().empty()) {
183 BluetoothSocketNet::Disconnect(callback);
184 } else {
185 DoCloseListening();
186 callback.Run();
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);
197 return;
200 // Only one pending accept at a time
201 if (accept_request_.get()) {
202 error_callback.Run(net::ErrorToString(net::ERR_IO_PENDING));
203 return;
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
224 // UUID.
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);
231 } else {
232 object_path_ = dbus::ObjectPath("/org/chromium/bluetooth_profile/" +
233 uuid_path);
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();
248 return;
251 VLOG(1) << object_path_.value() << ": Registering profile.";
252 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
253 RegisterProfile(
254 object_path_,
255 uuid_.canonical_value(),
256 *options_,
257 base::Bind(&BluetoothSocketChromeOS::OnRegisterProfile,
258 this,
259 success_callback,
260 error_callback),
261 base::Bind(&BluetoothSocketChromeOS::OnRegisterProfileError,
262 this,
263 error_callback));
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()->
275 ConnectProfile(
276 device_path_,
277 uuid_.canonical_value(),
278 base::Bind(
279 &BluetoothSocketChromeOS::OnConnectProfile,
280 this,
281 success_callback),
282 base::Bind(
283 &BluetoothSocketChromeOS::OnConnectProfileError,
284 this,
285 error_callback));
286 } else {
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.";
306 UnregisterProfile();
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;
317 UnregisterProfile();
318 error_callback.Run(error_message);
321 void BluetoothSocketChromeOS::AdapterPresentChanged(BluetoothAdapter* adapter,
322 bool present) {
323 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
324 DCHECK(!object_path_.value().empty());
325 DCHECK(profile_.get());
327 if (!present)
328 return;
330 VLOG(1) << object_path_.value() << ": Re-register profile.";
331 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
332 RegisterProfile(
333 object_path_,
334 uuid_.canonical_value(),
335 *options_,
336 base::Bind(&BluetoothSocketChromeOS::OnInternalRegisterProfile,
337 this),
338 base::Bind(&BluetoothSocketChromeOS::OnInternalRegisterProfileError,
339 this));
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
354 // initialization.
355 if (error_name == bluetooth_profile_manager::kErrorAlreadyExists)
356 return;
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(
380 FROM_HERE,
381 base::Bind(
382 &BluetoothSocketChromeOS::DoNewConnection,
383 this,
384 device_path_,
385 base::Passed(&fd),
386 options,
387 callback));
388 } else {
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())
416 return;
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;
423 } else {
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);
441 DCHECK(device);
443 scoped_refptr<BluetoothSocketChromeOS> client_socket =
444 BluetoothSocketChromeOS::CreateBluetoothSocket(
445 ui_task_runner(),
446 socket_thread(),
447 net_log(),
448 source());
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(
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)));
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();
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));;
481 return;
484 if (tcp_socket()) {
485 LOG(WARNING) << object_path_.value() << ": Already connected";
486 ui_task_runner()->PostTask(FROM_HERE,
487 base::Bind(callback, REJECTED));;
488 return;
491 ResetTCPSocket();
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(),
496 net::IPEndPoint());
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));;
502 return;
505 fd->TakeValue();
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,
513 Status status) {
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);
523 DCHECK(device);
525 accept_request_->success_callback.Run(device, socket);
526 } else {
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()->
559 UnregisterProfile(
560 object_path_,
561 base::Bind(&BluetoothSocketChromeOS::OnUnregisterProfile,
562 this,
563 object_path_),
564 base::Bind(&BluetoothSocketChromeOS::OnUnregisterProfileError,
565 this,
566 object_path_));
568 profile_.reset();
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
582 // yet.
583 if (error_name == bluetooth_profile_manager::kErrorDoesNotExist)
584 return;
586 LOG(WARNING) << object_path_.value() << ": Failed to unregister profile: "
587 << error_name << ": " << error_message;
590 } // namespace chromeos