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::core_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(
198 new Event(bluetooth_socket::OnReceive::kEventName
, args
.Pass()));
199 PostEvent(params
, event
.Pass());
201 // Post a task to delay the read until the socket is available, as
202 // calling StartReceive at this point would error with ERR_IO_PENDING.
203 BrowserThread::PostTask(
206 base::Bind(&BluetoothSocketEventDispatcher::StartReceive
, params
));
210 void BluetoothSocketEventDispatcher::ReceiveErrorCallback(
211 const SocketParams
& params
,
212 BluetoothApiSocket::ErrorReason error_reason
,
213 const std::string
& error
) {
214 DCHECK(BrowserThread::CurrentlyOn(params
.thread_id
));
216 if (error_reason
== BluetoothApiSocket::kIOPending
) {
217 // This happens when resuming a socket which already had an active "read"
218 // callback. We can safely ignore this error, as the application should not
223 // Dispatch "onReceiveError" event but don't start another read to avoid
224 // potential infinite reads if we have a persistent network error.
225 bluetooth_socket::ReceiveErrorInfo receive_error_info
;
226 receive_error_info
.socket_id
= params
.socket_id
;
227 receive_error_info
.error_message
= error
;
228 receive_error_info
.error
= MapReceiveErrorReason(error_reason
);
229 scoped_ptr
<base::ListValue
> args
=
230 bluetooth_socket::OnReceiveError::Create(receive_error_info
);
231 scoped_ptr
<Event
> event(
232 new Event(bluetooth_socket::OnReceiveError::kEventName
, args
.Pass()));
233 PostEvent(params
, event
.Pass());
235 // Since we got an error, the socket is now "paused" until the application
237 BluetoothApiSocket
* socket
=
238 params
.sockets
->Get(params
.extension_id
, params
.socket_id
);
240 socket
->set_paused(true);
245 void BluetoothSocketEventDispatcher::StartAccept(const SocketParams
& params
) {
246 DCHECK(BrowserThread::CurrentlyOn(params
.thread_id
));
248 BluetoothApiSocket
* socket
=
249 params
.sockets
->Get(params
.extension_id
, params
.socket_id
);
251 // This can happen if the socket is closed while our callback is active.
254 DCHECK(params
.extension_id
== socket
->owner_extension_id())
255 << "Socket has wrong owner.";
257 // Don't start another accept if the socket has been paused.
258 if (socket
->paused())
263 &BluetoothSocketEventDispatcher::AcceptCallback
, params
),
265 &BluetoothSocketEventDispatcher::AcceptErrorCallback
, params
));
269 void BluetoothSocketEventDispatcher::AcceptCallback(
270 const SocketParams
& params
,
271 const device::BluetoothDevice
* device
,
272 scoped_refptr
<device::BluetoothSocket
> socket
) {
273 DCHECK(BrowserThread::CurrentlyOn(params
.thread_id
));
275 BluetoothApiSocket
* server_api_socket
=
276 params
.sockets
->Get(params
.extension_id
, params
.socket_id
);
277 DCHECK(server_api_socket
);
279 BluetoothApiSocket
* client_api_socket
= new BluetoothApiSocket(
282 device
->GetAddress(),
283 server_api_socket
->uuid());
284 int client_socket_id
= params
.sockets
->Add(client_api_socket
);
286 // Dispatch "onAccept" event.
287 bluetooth_socket::AcceptInfo accept_info
;
288 accept_info
.socket_id
= params
.socket_id
;
289 accept_info
.client_socket_id
= client_socket_id
;
290 scoped_ptr
<base::ListValue
> args
=
291 bluetooth_socket::OnAccept::Create(accept_info
);
292 scoped_ptr
<Event
> event(
293 new Event(bluetooth_socket::OnAccept::kEventName
, args
.Pass()));
294 PostEvent(params
, event
.Pass());
296 // Post a task to delay the accept until the socket is available, as
297 // calling StartAccept at this point would error with ERR_IO_PENDING.
298 BrowserThread::PostTask(
301 base::Bind(&BluetoothSocketEventDispatcher::StartAccept
, params
));
305 void BluetoothSocketEventDispatcher::AcceptErrorCallback(
306 const SocketParams
& params
,
307 BluetoothApiSocket::ErrorReason error_reason
,
308 const std::string
& error
) {
309 DCHECK(BrowserThread::CurrentlyOn(params
.thread_id
));
311 if (error_reason
== BluetoothApiSocket::kIOPending
) {
312 // This happens when resuming a socket which already had an active "accept"
313 // callback. We can safely ignore this error, as the application should not
318 // Dispatch "onAcceptError" event but don't start another accept to avoid
319 // potential infinite accepts if we have a persistent network error.
320 bluetooth_socket::AcceptErrorInfo accept_error_info
;
321 accept_error_info
.socket_id
= params
.socket_id
;
322 accept_error_info
.error_message
= error
;
323 accept_error_info
.error
= MapAcceptErrorReason(error_reason
);
324 scoped_ptr
<base::ListValue
> args
=
325 bluetooth_socket::OnAcceptError::Create(accept_error_info
);
326 scoped_ptr
<Event
> event(
327 new Event(bluetooth_socket::OnAcceptError::kEventName
, args
.Pass()));
328 PostEvent(params
, event
.Pass());
330 // Since we got an error, the socket is now "paused" until the application
332 BluetoothApiSocket
* socket
=
333 params
.sockets
->Get(params
.extension_id
, params
.socket_id
);
335 socket
->set_paused(true);
340 void BluetoothSocketEventDispatcher::PostEvent(const SocketParams
& params
,
341 scoped_ptr
<Event
> event
) {
342 DCHECK(BrowserThread::CurrentlyOn(params
.thread_id
));
344 BrowserThread::PostTask(
347 base::Bind(&DispatchEvent
,
348 params
.browser_context_id
,
350 base::Passed(event
.Pass())));
354 void BluetoothSocketEventDispatcher::DispatchEvent(
355 void* browser_context_id
,
356 const std::string
& extension_id
,
357 scoped_ptr
<Event
> event
) {
358 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
360 content::BrowserContext
* context
=
361 reinterpret_cast<content::BrowserContext
*>(browser_context_id
);
362 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context
))
365 EventRouter
* router
= EventRouter::Get(context
);
367 router
->DispatchEventToExtension(extension_id
, event
.Pass());
370 } // namespace core_api
371 } // namespace extensions