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_event_dispatcher.h"
7 #include "base/lazy_instance.h"
8 #include "device/bluetooth/bluetooth_device.h"
9 #include "device/bluetooth/bluetooth_socket.h"
10 #include "extensions/browser/api/bluetooth_socket/bluetooth_api_socket.h"
11 #include "extensions/browser/event_router.h"
12 #include "extensions/common/api/bluetooth_socket.h"
13 #include "net/base/io_buffer.h"
17 namespace bluetooth_socket
= extensions::api::bluetooth_socket
;
18 using extensions::BluetoothApiSocket
;
20 int kDefaultBufferSize
= 4096;
22 bluetooth_socket::ReceiveError
MapReceiveErrorReason(
23 BluetoothApiSocket::ErrorReason value
) {
25 case BluetoothApiSocket::kDisconnected
:
26 return bluetooth_socket::RECEIVE_ERROR_DISCONNECTED
;
27 case BluetoothApiSocket::kNotConnected
:
28 // kNotConnected is impossible since a socket has to be connected to be
29 // able to call Receive() on it.
31 case BluetoothApiSocket::kIOPending
:
32 // kIOPending is not relevant to apps, as BluetoothSocketEventDispatcher
33 // handles this specific error.
36 return bluetooth_socket::RECEIVE_ERROR_SYSTEM_ERROR
;
40 bluetooth_socket::AcceptError
MapAcceptErrorReason(
41 BluetoothApiSocket::ErrorReason value
) {
42 // TODO(keybuk): All values are system error, we may want to seperate these
43 // out to more discrete reasons.
45 case BluetoothApiSocket::kNotListening
:
46 // kNotListening is impossible since a socket has to be listening to be
47 // able to call Accept() on it.
50 return bluetooth_socket::ACCEPT_ERROR_SYSTEM_ERROR
;
56 namespace extensions
{
59 using content::BrowserThread
;
61 static base::LazyInstance
<
62 BrowserContextKeyedAPIFactory
<BluetoothSocketEventDispatcher
> > g_factory
=
63 LAZY_INSTANCE_INITIALIZER
;
66 BrowserContextKeyedAPIFactory
<BluetoothSocketEventDispatcher
>*
67 BluetoothSocketEventDispatcher::GetFactoryInstance() {
68 return g_factory
.Pointer();
72 BluetoothSocketEventDispatcher
* BluetoothSocketEventDispatcher::Get(
73 content::BrowserContext
* context
) {
74 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
76 return BrowserContextKeyedAPIFactory
<BluetoothSocketEventDispatcher
>::Get(
80 BluetoothSocketEventDispatcher::BluetoothSocketEventDispatcher(
81 content::BrowserContext
* context
)
82 : thread_id_(BluetoothApiSocket::kThreadId
),
83 browser_context_(context
) {
84 ApiResourceManager
<BluetoothApiSocket
>* manager
=
85 ApiResourceManager
<BluetoothApiSocket
>::Get(browser_context_
);
87 << "There is no socket manager. "
88 "If this assertion is failing during a test, then it is likely that "
89 "TestExtensionSystem is failing to provide an instance of "
90 "ApiResourceManager<BluetoothApiSocket>.";
91 sockets_
= manager
->data_
;
94 BluetoothSocketEventDispatcher::~BluetoothSocketEventDispatcher() {}
96 BluetoothSocketEventDispatcher::SocketParams::SocketParams() {}
98 BluetoothSocketEventDispatcher::SocketParams::~SocketParams() {}
100 void BluetoothSocketEventDispatcher::OnSocketConnect(
101 const std::string
& extension_id
,
103 DCHECK(BrowserThread::CurrentlyOn(thread_id_
));
106 params
.thread_id
= thread_id_
;
107 params
.browser_context_id
= browser_context_
;
108 params
.extension_id
= extension_id
;
109 params
.sockets
= sockets_
;
110 params
.socket_id
= socket_id
;
112 StartReceive(params
);
115 void BluetoothSocketEventDispatcher::OnSocketListen(
116 const std::string
& extension_id
,
118 DCHECK(BrowserThread::CurrentlyOn(thread_id_
));
121 params
.thread_id
= thread_id_
;
122 params
.browser_context_id
= browser_context_
;
123 params
.extension_id
= extension_id
;
124 params
.sockets
= sockets_
;
125 params
.socket_id
= socket_id
;
130 void BluetoothSocketEventDispatcher::OnSocketResume(
131 const std::string
& extension_id
,
133 DCHECK(BrowserThread::CurrentlyOn(thread_id_
));
136 params
.thread_id
= thread_id_
;
137 params
.browser_context_id
= browser_context_
;
138 params
.extension_id
= extension_id
;
139 params
.sockets
= sockets_
;
140 params
.socket_id
= socket_id
;
142 BluetoothApiSocket
* socket
=
143 params
.sockets
->Get(params
.extension_id
, params
.socket_id
);
145 // This can happen if the socket is closed while our callback is active.
149 if (socket
->IsConnected()) {
150 StartReceive(params
);
157 void BluetoothSocketEventDispatcher::StartReceive(const SocketParams
& params
) {
158 DCHECK(BrowserThread::CurrentlyOn(params
.thread_id
));
160 BluetoothApiSocket
* socket
=
161 params
.sockets
->Get(params
.extension_id
, params
.socket_id
);
163 // This can happen if the socket is closed while our callback is active.
166 DCHECK(params
.extension_id
== socket
->owner_extension_id())
167 << "Socket has wrong owner.";
169 // Don't start another read if the socket has been paused.
170 if (socket
->paused())
173 int buffer_size
= socket
->buffer_size();
174 if (buffer_size
<= 0)
175 buffer_size
= kDefaultBufferSize
;
179 &BluetoothSocketEventDispatcher::ReceiveCallback
, params
),
181 &BluetoothSocketEventDispatcher::ReceiveErrorCallback
, params
));
185 void BluetoothSocketEventDispatcher::ReceiveCallback(
186 const SocketParams
& params
,
188 scoped_refptr
<net::IOBuffer
> io_buffer
) {
189 DCHECK(BrowserThread::CurrentlyOn(params
.thread_id
));
191 // Dispatch "onReceive" event.
192 bluetooth_socket::ReceiveInfo receive_info
;
193 receive_info
.socket_id
= params
.socket_id
;
194 receive_info
.data
.assign(io_buffer
->data(), io_buffer
->data() + bytes_read
);
195 scoped_ptr
<base::ListValue
> args
=
196 bluetooth_socket::OnReceive::Create(receive_info
);
197 scoped_ptr
<Event
> event(new Event(events::BLUETOOTH_SOCKET_ON_RECEIVE
,
198 bluetooth_socket::OnReceive::kEventName
,
200 PostEvent(params
, event
.Pass());
202 // Post a task to delay the read until the socket is available, as
203 // calling StartReceive at this point would error with ERR_IO_PENDING.
204 BrowserThread::PostTask(
207 base::Bind(&BluetoothSocketEventDispatcher::StartReceive
, params
));
211 void BluetoothSocketEventDispatcher::ReceiveErrorCallback(
212 const SocketParams
& params
,
213 BluetoothApiSocket::ErrorReason error_reason
,
214 const std::string
& error
) {
215 DCHECK(BrowserThread::CurrentlyOn(params
.thread_id
));
217 if (error_reason
== BluetoothApiSocket::kIOPending
) {
218 // This happens when resuming a socket which already had an active "read"
219 // callback. We can safely ignore this error, as the application should not
224 // Dispatch "onReceiveError" event but don't start another read to avoid
225 // potential infinite reads if we have a persistent network error.
226 bluetooth_socket::ReceiveErrorInfo receive_error_info
;
227 receive_error_info
.socket_id
= params
.socket_id
;
228 receive_error_info
.error_message
= error
;
229 receive_error_info
.error
= MapReceiveErrorReason(error_reason
);
230 scoped_ptr
<base::ListValue
> args
=
231 bluetooth_socket::OnReceiveError::Create(receive_error_info
);
232 scoped_ptr
<Event
> event(
233 new Event(events::BLUETOOTH_SOCKET_ON_RECEIVE_ERROR
,
234 bluetooth_socket::OnReceiveError::kEventName
, args
.Pass()));
235 PostEvent(params
, event
.Pass());
237 // Since we got an error, the socket is now "paused" until the application
239 BluetoothApiSocket
* socket
=
240 params
.sockets
->Get(params
.extension_id
, params
.socket_id
);
242 socket
->set_paused(true);
247 void BluetoothSocketEventDispatcher::StartAccept(const SocketParams
& params
) {
248 DCHECK(BrowserThread::CurrentlyOn(params
.thread_id
));
250 BluetoothApiSocket
* socket
=
251 params
.sockets
->Get(params
.extension_id
, params
.socket_id
);
253 // This can happen if the socket is closed while our callback is active.
256 DCHECK(params
.extension_id
== socket
->owner_extension_id())
257 << "Socket has wrong owner.";
259 // Don't start another accept if the socket has been paused.
260 if (socket
->paused())
265 &BluetoothSocketEventDispatcher::AcceptCallback
, params
),
267 &BluetoothSocketEventDispatcher::AcceptErrorCallback
, params
));
271 void BluetoothSocketEventDispatcher::AcceptCallback(
272 const SocketParams
& params
,
273 const device::BluetoothDevice
* device
,
274 scoped_refptr
<device::BluetoothSocket
> socket
) {
275 DCHECK(BrowserThread::CurrentlyOn(params
.thread_id
));
277 BluetoothApiSocket
* server_api_socket
=
278 params
.sockets
->Get(params
.extension_id
, params
.socket_id
);
279 DCHECK(server_api_socket
);
281 BluetoothApiSocket
* client_api_socket
= new BluetoothApiSocket(
284 device
->GetAddress(),
285 server_api_socket
->uuid());
286 int client_socket_id
= params
.sockets
->Add(client_api_socket
);
288 // Dispatch "onAccept" event.
289 bluetooth_socket::AcceptInfo accept_info
;
290 accept_info
.socket_id
= params
.socket_id
;
291 accept_info
.client_socket_id
= client_socket_id
;
292 scoped_ptr
<base::ListValue
> args
=
293 bluetooth_socket::OnAccept::Create(accept_info
);
294 scoped_ptr
<Event
> event(new Event(events::BLUETOOTH_SOCKET_ON_ACCEPT
,
295 bluetooth_socket::OnAccept::kEventName
,
297 PostEvent(params
, event
.Pass());
299 // Post a task to delay the accept until the socket is available, as
300 // calling StartAccept at this point would error with ERR_IO_PENDING.
301 BrowserThread::PostTask(
304 base::Bind(&BluetoothSocketEventDispatcher::StartAccept
, params
));
308 void BluetoothSocketEventDispatcher::AcceptErrorCallback(
309 const SocketParams
& params
,
310 BluetoothApiSocket::ErrorReason error_reason
,
311 const std::string
& error
) {
312 DCHECK(BrowserThread::CurrentlyOn(params
.thread_id
));
314 if (error_reason
== BluetoothApiSocket::kIOPending
) {
315 // This happens when resuming a socket which already had an active "accept"
316 // callback. We can safely ignore this error, as the application should not
321 // Dispatch "onAcceptError" event but don't start another accept to avoid
322 // potential infinite accepts if we have a persistent network error.
323 bluetooth_socket::AcceptErrorInfo accept_error_info
;
324 accept_error_info
.socket_id
= params
.socket_id
;
325 accept_error_info
.error_message
= error
;
326 accept_error_info
.error
= MapAcceptErrorReason(error_reason
);
327 scoped_ptr
<base::ListValue
> args
=
328 bluetooth_socket::OnAcceptError::Create(accept_error_info
);
329 scoped_ptr
<Event
> event(new Event(events::BLUETOOTH_SOCKET_ON_ACCEPT_ERROR
,
330 bluetooth_socket::OnAcceptError::kEventName
,
332 PostEvent(params
, event
.Pass());
334 // Since we got an error, the socket is now "paused" until the application
336 BluetoothApiSocket
* socket
=
337 params
.sockets
->Get(params
.extension_id
, params
.socket_id
);
339 socket
->set_paused(true);
344 void BluetoothSocketEventDispatcher::PostEvent(const SocketParams
& params
,
345 scoped_ptr
<Event
> event
) {
346 DCHECK(BrowserThread::CurrentlyOn(params
.thread_id
));
348 BrowserThread::PostTask(
351 base::Bind(&DispatchEvent
,
352 params
.browser_context_id
,
354 base::Passed(event
.Pass())));
358 void BluetoothSocketEventDispatcher::DispatchEvent(
359 void* browser_context_id
,
360 const std::string
& extension_id
,
361 scoped_ptr
<Event
> event
) {
362 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
364 content::BrowserContext
* context
=
365 reinterpret_cast<content::BrowserContext
*>(browser_context_id
);
366 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context
))
369 EventRouter
* router
= EventRouter::Get(context
);
371 router
->DispatchEventToExtension(extension_id
, event
.Pass());
375 } // namespace extensions