1 // Copyright 2014 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 "extensions/browser/api/bluetooth_socket/bluetooth_socket_api.h"
9 #include "content/public/browser/browser_context.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "device/bluetooth/bluetooth_adapter.h"
12 #include "device/bluetooth/bluetooth_adapter_factory.h"
13 #include "device/bluetooth/bluetooth_device.h"
14 #include "device/bluetooth/bluetooth_socket.h"
15 #include "extensions/browser/api/bluetooth_socket/bluetooth_api_socket.h"
16 #include "extensions/browser/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h"
17 #include "extensions/common/api/bluetooth/bluetooth_manifest_data.h"
18 #include "extensions/common/permissions/permissions_data.h"
19 #include "net/base/io_buffer.h"
21 using content::BrowserThread
;
22 using extensions::BluetoothApiSocket
;
23 using extensions::core_api::bluetooth_socket::ListenOptions
;
24 using extensions::core_api::bluetooth_socket::SocketInfo
;
25 using extensions::core_api::bluetooth_socket::SocketProperties
;
27 namespace extensions
{
32 const char kDeviceNotFoundError
[] = "Device not found";
33 const char kInvalidPsmError
[] = "Invalid PSM";
34 const char kInvalidUuidError
[] = "Invalid UUID";
35 const char kPermissionDeniedError
[] = "Permission denied";
36 const char kSocketNotFoundError
[] = "Socket not found";
38 linked_ptr
<SocketInfo
> CreateSocketInfo(int socket_id
,
39 BluetoothApiSocket
* socket
) {
40 DCHECK(BrowserThread::CurrentlyOn(BluetoothApiSocket::kThreadId
));
41 linked_ptr
<SocketInfo
> socket_info(new SocketInfo());
42 // This represents what we know about the socket, and does not call through
44 socket_info
->socket_id
= socket_id
;
46 socket_info
->name
.reset(new std::string(*socket
->name()));
48 socket_info
->persistent
= socket
->persistent();
49 if (socket
->buffer_size() > 0) {
50 socket_info
->buffer_size
.reset(new int(socket
->buffer_size()));
52 socket_info
->paused
= socket
->paused();
53 socket_info
->connected
= socket
->IsConnected();
55 if (socket
->IsConnected())
56 socket_info
->address
.reset(new std::string(socket
->device_address()));
57 socket_info
->uuid
.reset(new std::string(socket
->uuid().canonical_value()));
62 void SetSocketProperties(BluetoothApiSocket
* socket
,
63 SocketProperties
* properties
) {
64 if (properties
->name
.get()) {
65 socket
->set_name(*properties
->name
.get());
67 if (properties
->persistent
.get()) {
68 socket
->set_persistent(*properties
->persistent
.get());
70 if (properties
->buffer_size
.get()) {
71 // buffer size is validated when issuing the actual Recv operation
73 socket
->set_buffer_size(*properties
->buffer_size
.get());
77 BluetoothSocketEventDispatcher
* GetSocketEventDispatcher(
78 content::BrowserContext
* browser_context
) {
79 BluetoothSocketEventDispatcher
* socket_event_dispatcher
=
80 BluetoothSocketEventDispatcher::Get(browser_context
);
81 DCHECK(socket_event_dispatcher
)
82 << "There is no socket event dispatcher. "
83 "If this assertion is failing during a test, then it is likely that "
84 "TestExtensionSystem is failing to provide an instance of "
85 "BluetoothSocketEventDispatcher.";
86 return socket_event_dispatcher
;
89 // Returns |true| if |psm| is a valid PSM.
90 // Per the Bluetooth specification, the PSM field must be at least two octets in
91 // length, with least significant bit of the least significant octet equal to
92 // '1' and the least significant bit of the most significant octet equal to '0'.
93 bool IsValidPsm(int psm
) {
97 std::vector
<int16_t> octets
;
99 octets
.push_back(psm
& 0xFF);
103 if (octets
.size() < 2U)
106 // The least significant bit of the least significant octet must be '1'.
107 if ((octets
.front() & 0x01) != 1)
110 // The least significant bit of the most significant octet must be '0'.
111 if ((octets
.back() & 0x01) != 0)
119 BluetoothSocketAsyncApiFunction::BluetoothSocketAsyncApiFunction() {}
121 BluetoothSocketAsyncApiFunction::~BluetoothSocketAsyncApiFunction() {}
123 bool BluetoothSocketAsyncApiFunction::RunAsync() {
124 if (!PrePrepare() || !Prepare()) {
131 bool BluetoothSocketAsyncApiFunction::PrePrepare() {
132 if (!BluetoothManifestData::CheckSocketPermitted(extension())) {
133 error_
= kPermissionDeniedError
;
137 manager_
= ApiResourceManager
<BluetoothApiSocket
>::Get(browser_context());
139 << "There is no socket manager. "
140 "If this assertion is failing during a test, then it is likely that "
141 "TestExtensionSystem is failing to provide an instance of "
142 "ApiResourceManager<BluetoothApiSocket>.";
143 return manager_
!= NULL
;
146 bool BluetoothSocketAsyncApiFunction::Respond() { return error_
.empty(); }
148 void BluetoothSocketAsyncApiFunction::AsyncWorkCompleted() {
149 SendResponse(Respond());
152 void BluetoothSocketAsyncApiFunction::Work() {}
154 void BluetoothSocketAsyncApiFunction::AsyncWorkStart() {
156 AsyncWorkCompleted();
159 int BluetoothSocketAsyncApiFunction::AddSocket(BluetoothApiSocket
* socket
) {
160 return manager_
->Add(socket
);
163 content::BrowserThread::ID
164 BluetoothSocketAsyncApiFunction::work_thread_id() const {
165 return BluetoothApiSocket::kThreadId
;
168 BluetoothApiSocket
* BluetoothSocketAsyncApiFunction::GetSocket(
169 int api_resource_id
) {
170 return manager_
->Get(extension_id(), api_resource_id
);
173 void BluetoothSocketAsyncApiFunction::RemoveSocket(int api_resource_id
) {
174 manager_
->Remove(extension_id(), api_resource_id
);
177 base::hash_set
<int>* BluetoothSocketAsyncApiFunction::GetSocketIds() {
178 return manager_
->GetResourceIds(extension_id());
181 BluetoothSocketCreateFunction::BluetoothSocketCreateFunction() {}
183 BluetoothSocketCreateFunction::~BluetoothSocketCreateFunction() {}
185 bool BluetoothSocketCreateFunction::Prepare() {
186 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
188 params_
= bluetooth_socket::Create::Params::Create(*args_
);
189 EXTENSION_FUNCTION_VALIDATE(params_
.get());
193 void BluetoothSocketCreateFunction::Work() {
194 DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
196 BluetoothApiSocket
* socket
= new BluetoothApiSocket(extension_id());
198 bluetooth_socket::SocketProperties
* properties
=
199 params_
.get()->properties
.get();
201 SetSocketProperties(socket
, properties
);
204 bluetooth_socket::CreateInfo create_info
;
205 create_info
.socket_id
= AddSocket(socket
);
206 results_
= bluetooth_socket::Create::Results::Create(create_info
);
207 AsyncWorkCompleted();
210 BluetoothSocketUpdateFunction::BluetoothSocketUpdateFunction() {}
212 BluetoothSocketUpdateFunction::~BluetoothSocketUpdateFunction() {}
214 bool BluetoothSocketUpdateFunction::Prepare() {
215 params_
= bluetooth_socket::Update::Params::Create(*args_
);
216 EXTENSION_FUNCTION_VALIDATE(params_
.get());
220 void BluetoothSocketUpdateFunction::Work() {
221 BluetoothApiSocket
* socket
= GetSocket(params_
->socket_id
);
223 error_
= kSocketNotFoundError
;
227 SetSocketProperties(socket
, ¶ms_
.get()->properties
);
228 results_
= bluetooth_socket::Update::Results::Create();
231 BluetoothSocketSetPausedFunction::BluetoothSocketSetPausedFunction()
232 : socket_event_dispatcher_(NULL
) {}
234 BluetoothSocketSetPausedFunction::~BluetoothSocketSetPausedFunction() {}
236 bool BluetoothSocketSetPausedFunction::Prepare() {
237 params_
= bluetooth_socket::SetPaused::Params::Create(*args_
);
238 EXTENSION_FUNCTION_VALIDATE(params_
.get());
240 socket_event_dispatcher_
= GetSocketEventDispatcher(browser_context());
241 return socket_event_dispatcher_
!= NULL
;
244 void BluetoothSocketSetPausedFunction::Work() {
245 BluetoothApiSocket
* socket
= GetSocket(params_
->socket_id
);
247 error_
= kSocketNotFoundError
;
251 if (socket
->paused() != params_
->paused
) {
252 socket
->set_paused(params_
->paused
);
253 if (!params_
->paused
) {
254 socket_event_dispatcher_
->OnSocketResume(extension_id(),
259 results_
= bluetooth_socket::SetPaused::Results::Create();
262 BluetoothSocketListenFunction::BluetoothSocketListenFunction() {}
264 BluetoothSocketListenFunction::~BluetoothSocketListenFunction() {}
266 bool BluetoothSocketListenFunction::Prepare() {
267 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
270 socket_event_dispatcher_
= GetSocketEventDispatcher(browser_context());
271 return socket_event_dispatcher_
!= NULL
;
274 void BluetoothSocketListenFunction::AsyncWorkStart() {
275 DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
276 device::BluetoothAdapterFactory::GetAdapter(
277 base::Bind(&BluetoothSocketListenFunction::OnGetAdapter
, this));
280 void BluetoothSocketListenFunction::OnGetAdapter(
281 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
282 DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
283 BluetoothApiSocket
* socket
= GetSocket(socket_id());
285 error_
= kSocketNotFoundError
;
286 AsyncWorkCompleted();
290 device::BluetoothUUID
bluetooth_uuid(uuid());
291 if (!bluetooth_uuid
.IsValid()) {
292 error_
= kInvalidUuidError
;
293 AsyncWorkCompleted();
297 BluetoothPermissionRequest
param(uuid());
298 if (!BluetoothManifestData::CheckRequest(extension(), param
)) {
299 error_
= kPermissionDeniedError
;
300 AsyncWorkCompleted();
304 scoped_ptr
<std::string
> name
;
306 name
.reset(new std::string(*socket
->name()));
312 base::Bind(&BluetoothSocketListenFunction::OnCreateService
, this),
313 base::Bind(&BluetoothSocketListenFunction::OnCreateServiceError
, this));
317 void BluetoothSocketListenFunction::OnCreateService(
318 scoped_refptr
<device::BluetoothSocket
> socket
) {
319 DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
321 // Fetch the socket again since this is not a reference-counted object, and
322 // it may have gone away in the meantime (we check earlier to avoid making
323 // a connection in the case of an obvious programming error).
324 BluetoothApiSocket
* api_socket
= GetSocket(socket_id());
326 error_
= kSocketNotFoundError
;
327 AsyncWorkCompleted();
331 api_socket
->AdoptListeningSocket(socket
,
332 device::BluetoothUUID(uuid()));
333 socket_event_dispatcher_
->OnSocketListen(extension_id(), socket_id());
336 AsyncWorkCompleted();
339 void BluetoothSocketListenFunction::OnCreateServiceError(
340 const std::string
& message
) {
341 DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
343 AsyncWorkCompleted();
346 BluetoothSocketListenUsingRfcommFunction::
347 BluetoothSocketListenUsingRfcommFunction() {}
349 BluetoothSocketListenUsingRfcommFunction::
350 ~BluetoothSocketListenUsingRfcommFunction() {}
352 int BluetoothSocketListenUsingRfcommFunction::socket_id() const {
353 return params_
->socket_id
;
356 const std::string
& BluetoothSocketListenUsingRfcommFunction::uuid() const {
357 return params_
->uuid
;
360 bool BluetoothSocketListenUsingRfcommFunction::CreateParams() {
361 params_
= bluetooth_socket::ListenUsingRfcomm::Params::Create(*args_
);
362 EXTENSION_FUNCTION_VALIDATE(params_
.get());
366 void BluetoothSocketListenUsingRfcommFunction::CreateService(
367 scoped_refptr
<device::BluetoothAdapter
> adapter
,
368 const device::BluetoothUUID
& uuid
,
369 scoped_ptr
<std::string
> name
,
370 const device::BluetoothAdapter::CreateServiceCallback
& callback
,
371 const device::BluetoothAdapter::CreateServiceErrorCallback
&
373 device::BluetoothAdapter::ServiceOptions service_options
;
374 service_options
.name
= name
.Pass();
376 ListenOptions
* options
= params_
->options
.get();
378 if (options
->channel
.get())
379 service_options
.channel
.reset(new int(*(options
->channel
)));
382 adapter
->CreateRfcommService(uuid
, service_options
, callback
, error_callback
);
385 void BluetoothSocketListenUsingRfcommFunction::CreateResults() {
386 results_
= bluetooth_socket::ListenUsingRfcomm::Results::Create();
389 BluetoothSocketListenUsingL2capFunction::
390 BluetoothSocketListenUsingL2capFunction() {}
392 BluetoothSocketListenUsingL2capFunction::
393 ~BluetoothSocketListenUsingL2capFunction() {}
395 int BluetoothSocketListenUsingL2capFunction::socket_id() const {
396 return params_
->socket_id
;
399 const std::string
& BluetoothSocketListenUsingL2capFunction::uuid() const {
400 return params_
->uuid
;
403 bool BluetoothSocketListenUsingL2capFunction::CreateParams() {
404 params_
= bluetooth_socket::ListenUsingL2cap::Params::Create(*args_
);
405 EXTENSION_FUNCTION_VALIDATE(params_
.get());
409 void BluetoothSocketListenUsingL2capFunction::CreateService(
410 scoped_refptr
<device::BluetoothAdapter
> adapter
,
411 const device::BluetoothUUID
& uuid
,
412 scoped_ptr
<std::string
> name
,
413 const device::BluetoothAdapter::CreateServiceCallback
& callback
,
414 const device::BluetoothAdapter::CreateServiceErrorCallback
&
416 device::BluetoothAdapter::ServiceOptions service_options
;
417 service_options
.name
= name
.Pass();
419 ListenOptions
* options
= params_
->options
.get();
422 int psm
= *options
->psm
;
423 if (!IsValidPsm(psm
)) {
424 error_callback
.Run(kInvalidPsmError
);
428 service_options
.psm
.reset(new int(psm
));
432 adapter
->CreateL2capService(uuid
, service_options
, callback
, error_callback
);
435 void BluetoothSocketListenUsingL2capFunction::CreateResults() {
436 results_
= bluetooth_socket::ListenUsingL2cap::Results::Create();
439 BluetoothSocketAbstractConnectFunction::
440 BluetoothSocketAbstractConnectFunction() {}
442 BluetoothSocketAbstractConnectFunction::
443 ~BluetoothSocketAbstractConnectFunction() {}
445 bool BluetoothSocketAbstractConnectFunction::Prepare() {
446 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
447 params_
= bluetooth_socket::Connect::Params::Create(*args_
);
448 EXTENSION_FUNCTION_VALIDATE(params_
.get());
450 socket_event_dispatcher_
= GetSocketEventDispatcher(browser_context());
451 return socket_event_dispatcher_
!= NULL
;
454 void BluetoothSocketAbstractConnectFunction::AsyncWorkStart() {
455 DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
456 device::BluetoothAdapterFactory::GetAdapter(
457 base::Bind(&BluetoothSocketAbstractConnectFunction::OnGetAdapter
, this));
460 void BluetoothSocketAbstractConnectFunction::OnGetAdapter(
461 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
462 DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
463 BluetoothApiSocket
* socket
= GetSocket(params_
->socket_id
);
465 error_
= kSocketNotFoundError
;
466 AsyncWorkCompleted();
470 device::BluetoothDevice
* device
= adapter
->GetDevice(params_
->address
);
472 error_
= kDeviceNotFoundError
;
473 AsyncWorkCompleted();
477 device::BluetoothUUID
uuid(params_
->uuid
);
478 if (!uuid
.IsValid()) {
479 error_
= kInvalidUuidError
;
480 AsyncWorkCompleted();
484 BluetoothPermissionRequest
param(params_
->uuid
);
485 if (!BluetoothManifestData::CheckRequest(extension(), param
)) {
486 error_
= kPermissionDeniedError
;
487 AsyncWorkCompleted();
491 ConnectToService(device
, uuid
);
494 void BluetoothSocketAbstractConnectFunction::OnConnect(
495 scoped_refptr
<device::BluetoothSocket
> socket
) {
496 DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
498 // Fetch the socket again since this is not a reference-counted object, and
499 // it may have gone away in the meantime (we check earlier to avoid making
500 // a connection in the case of an obvious programming error).
501 BluetoothApiSocket
* api_socket
= GetSocket(params_
->socket_id
);
503 error_
= kSocketNotFoundError
;
504 AsyncWorkCompleted();
508 api_socket
->AdoptConnectedSocket(socket
,
510 device::BluetoothUUID(params_
->uuid
));
511 socket_event_dispatcher_
->OnSocketConnect(extension_id(),
514 results_
= bluetooth_socket::Connect::Results::Create();
515 AsyncWorkCompleted();
518 void BluetoothSocketAbstractConnectFunction::OnConnectError(
519 const std::string
& message
) {
520 DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
522 AsyncWorkCompleted();
525 BluetoothSocketConnectFunction::BluetoothSocketConnectFunction() {}
527 BluetoothSocketConnectFunction::~BluetoothSocketConnectFunction() {}
529 void BluetoothSocketConnectFunction::ConnectToService(
530 device::BluetoothDevice
* device
,
531 const device::BluetoothUUID
& uuid
) {
532 device
->ConnectToService(
534 base::Bind(&BluetoothSocketConnectFunction::OnConnect
, this),
535 base::Bind(&BluetoothSocketConnectFunction::OnConnectError
, this));
538 BluetoothSocketDisconnectFunction::BluetoothSocketDisconnectFunction() {}
540 BluetoothSocketDisconnectFunction::~BluetoothSocketDisconnectFunction() {}
542 bool BluetoothSocketDisconnectFunction::Prepare() {
543 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
544 params_
= bluetooth_socket::Disconnect::Params::Create(*args_
);
545 EXTENSION_FUNCTION_VALIDATE(params_
.get());
549 void BluetoothSocketDisconnectFunction::AsyncWorkStart() {
550 DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
551 BluetoothApiSocket
* socket
= GetSocket(params_
->socket_id
);
553 error_
= kSocketNotFoundError
;
554 AsyncWorkCompleted();
558 socket
->Disconnect(base::Bind(&BluetoothSocketDisconnectFunction::OnSuccess
,
562 void BluetoothSocketDisconnectFunction::OnSuccess() {
563 DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
564 results_
= bluetooth_socket::Disconnect::Results::Create();
565 AsyncWorkCompleted();
568 BluetoothSocketCloseFunction::BluetoothSocketCloseFunction() {}
570 BluetoothSocketCloseFunction::~BluetoothSocketCloseFunction() {}
572 bool BluetoothSocketCloseFunction::Prepare() {
573 params_
= bluetooth_socket::Close::Params::Create(*args_
);
574 EXTENSION_FUNCTION_VALIDATE(params_
.get());
578 void BluetoothSocketCloseFunction::Work() {
579 BluetoothApiSocket
* socket
= GetSocket(params_
->socket_id
);
581 error_
= kSocketNotFoundError
;
585 RemoveSocket(params_
->socket_id
);
586 results_
= bluetooth_socket::Close::Results::Create();
589 BluetoothSocketSendFunction::BluetoothSocketSendFunction()
590 : io_buffer_size_(0) {}
592 BluetoothSocketSendFunction::~BluetoothSocketSendFunction() {}
594 bool BluetoothSocketSendFunction::Prepare() {
595 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
596 params_
= bluetooth_socket::Send::Params::Create(*args_
);
597 EXTENSION_FUNCTION_VALIDATE(params_
.get());
599 io_buffer_size_
= params_
->data
.size();
600 io_buffer_
= new net::WrappedIOBuffer(params_
->data
.data());
604 void BluetoothSocketSendFunction::AsyncWorkStart() {
605 DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
606 BluetoothApiSocket
* socket
= GetSocket(params_
->socket_id
);
608 error_
= kSocketNotFoundError
;
612 socket
->Send(io_buffer_
,
614 base::Bind(&BluetoothSocketSendFunction::OnSuccess
, this),
615 base::Bind(&BluetoothSocketSendFunction::OnError
, this));
618 void BluetoothSocketSendFunction::OnSuccess(int bytes_sent
) {
619 DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
620 results_
= bluetooth_socket::Send::Results::Create(bytes_sent
);
621 AsyncWorkCompleted();
624 void BluetoothSocketSendFunction::OnError(
625 BluetoothApiSocket::ErrorReason reason
,
626 const std::string
& message
) {
627 DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
629 AsyncWorkCompleted();
632 BluetoothSocketGetInfoFunction::BluetoothSocketGetInfoFunction() {}
634 BluetoothSocketGetInfoFunction::~BluetoothSocketGetInfoFunction() {}
636 bool BluetoothSocketGetInfoFunction::Prepare() {
637 params_
= bluetooth_socket::GetInfo::Params::Create(*args_
);
638 EXTENSION_FUNCTION_VALIDATE(params_
.get());
642 void BluetoothSocketGetInfoFunction::Work() {
643 BluetoothApiSocket
* socket
= GetSocket(params_
->socket_id
);
645 error_
= kSocketNotFoundError
;
649 linked_ptr
<bluetooth_socket::SocketInfo
> socket_info
=
650 CreateSocketInfo(params_
->socket_id
, socket
);
651 results_
= bluetooth_socket::GetInfo::Results::Create(*socket_info
);
654 BluetoothSocketGetSocketsFunction::BluetoothSocketGetSocketsFunction() {}
656 BluetoothSocketGetSocketsFunction::~BluetoothSocketGetSocketsFunction() {}
658 bool BluetoothSocketGetSocketsFunction::Prepare() { return true; }
660 void BluetoothSocketGetSocketsFunction::Work() {
661 std::vector
<linked_ptr
<bluetooth_socket::SocketInfo
> > socket_infos
;
662 base::hash_set
<int>* resource_ids
= GetSocketIds();
663 if (resource_ids
!= NULL
) {
664 for (base::hash_set
<int>::iterator it
= resource_ids
->begin();
665 it
!= resource_ids
->end();
668 BluetoothApiSocket
* socket
= GetSocket(socket_id
);
670 socket_infos
.push_back(CreateSocketInfo(socket_id
, socket
));
674 results_
= bluetooth_socket::GetSockets::Results::Create(socket_infos
);
677 } // namespace core_api
678 } // namespace extensions