Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / extensions / browser / api / bluetooth_socket / bluetooth_socket_event_dispatcher.cc
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.
4
5 #include "extensions/browser/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h"
6
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"
14
15 namespace {
16
17 namespace bluetooth_socket = extensions::core_api::bluetooth_socket;
18 using extensions::BluetoothApiSocket;
19
20 int kDefaultBufferSize = 4096;
21
22 bluetooth_socket::ReceiveError MapReceiveErrorReason(
23     BluetoothApiSocket::ErrorReason value) {
24   switch (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.
30     // fallthrough
31     case BluetoothApiSocket::kIOPending:
32     // kIOPending is not relevant to apps, as BluetoothSocketEventDispatcher
33     // handles this specific error.
34     // fallthrough
35     default:
36       return bluetooth_socket::RECEIVE_ERROR_SYSTEM_ERROR;
37   }
38 }
39
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.
44   switch (value) {
45     case BluetoothApiSocket::kNotListening:
46     // kNotListening is impossible since a socket has to be listening to be
47     // able to call Accept() on it.
48     // fallthrough
49     default:
50       return bluetooth_socket::ACCEPT_ERROR_SYSTEM_ERROR;
51   }
52 }
53
54 }  // namespace
55
56 namespace extensions {
57 namespace core_api {
58
59 using content::BrowserThread;
60
61 static base::LazyInstance<
62     BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher> > g_factory =
63     LAZY_INSTANCE_INITIALIZER;
64
65 // static
66 BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher>*
67 BluetoothSocketEventDispatcher::GetFactoryInstance() {
68   return g_factory.Pointer();
69 }
70
71 // static
72 BluetoothSocketEventDispatcher* BluetoothSocketEventDispatcher::Get(
73     content::BrowserContext* context) {
74   DCHECK_CURRENTLY_ON(BrowserThread::UI);
75
76   return BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher>::Get(
77       context);
78 }
79
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_);
86   DCHECK(manager)
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_;
92 }
93
94 BluetoothSocketEventDispatcher::~BluetoothSocketEventDispatcher() {}
95
96 BluetoothSocketEventDispatcher::SocketParams::SocketParams() {}
97
98 BluetoothSocketEventDispatcher::SocketParams::~SocketParams() {}
99
100 void BluetoothSocketEventDispatcher::OnSocketConnect(
101     const std::string& extension_id,
102     int socket_id) {
103   DCHECK(BrowserThread::CurrentlyOn(thread_id_));
104
105   SocketParams params;
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;
111
112   StartReceive(params);
113 }
114
115 void BluetoothSocketEventDispatcher::OnSocketListen(
116     const std::string& extension_id,
117     int socket_id) {
118   DCHECK(BrowserThread::CurrentlyOn(thread_id_));
119
120   SocketParams params;
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;
126
127   StartAccept(params);
128 }
129
130 void BluetoothSocketEventDispatcher::OnSocketResume(
131     const std::string& extension_id,
132     int socket_id) {
133   DCHECK(BrowserThread::CurrentlyOn(thread_id_));
134
135   SocketParams params;
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;
141
142   BluetoothApiSocket* socket =
143       params.sockets->Get(params.extension_id, params.socket_id);
144   if (!socket) {
145     // This can happen if the socket is closed while our callback is active.
146     return;
147   }
148
149   if (socket->IsConnected()) {
150     StartReceive(params);
151   } else {
152     StartAccept(params);
153   }
154 }
155
156 // static
157 void BluetoothSocketEventDispatcher::StartReceive(const SocketParams& params) {
158   DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
159
160   BluetoothApiSocket* socket =
161       params.sockets->Get(params.extension_id, params.socket_id);
162   if (!socket) {
163     // This can happen if the socket is closed while our callback is active.
164     return;
165   }
166   DCHECK(params.extension_id == socket->owner_extension_id())
167       << "Socket has wrong owner.";
168
169   // Don't start another read if the socket has been paused.
170   if (socket->paused())
171     return;
172
173   int buffer_size = socket->buffer_size();
174   if (buffer_size <= 0)
175     buffer_size = kDefaultBufferSize;
176   socket->Receive(
177       buffer_size,
178       base::Bind(
179           &BluetoothSocketEventDispatcher::ReceiveCallback, params),
180       base::Bind(
181           &BluetoothSocketEventDispatcher::ReceiveErrorCallback, params));
182 }
183
184 // static
185 void BluetoothSocketEventDispatcher::ReceiveCallback(
186     const SocketParams& params,
187     int bytes_read,
188     scoped_refptr<net::IOBuffer> io_buffer) {
189   DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
190
191   // Dispatch "onReceive" event.
192   bluetooth_socket::ReceiveInfo receive_info;
193   receive_info.socket_id = params.socket_id;
194   receive_info.data = std::string(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());
200
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(
204       params.thread_id,
205       FROM_HERE,
206       base::Bind(&BluetoothSocketEventDispatcher::StartReceive, params));
207 }
208
209 // static
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));
215
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
219     // care.
220     return;
221   }
222
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());
234
235   // Since we got an error, the socket is now "paused" until the application
236   // "resumes" it.
237   BluetoothApiSocket* socket =
238       params.sockets->Get(params.extension_id, params.socket_id);
239   if (socket) {
240     socket->set_paused(true);
241   }
242 }
243
244 // static
245 void BluetoothSocketEventDispatcher::StartAccept(const SocketParams& params) {
246   DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
247
248   BluetoothApiSocket* socket =
249       params.sockets->Get(params.extension_id, params.socket_id);
250   if (!socket) {
251     // This can happen if the socket is closed while our callback is active.
252     return;
253   }
254   DCHECK(params.extension_id == socket->owner_extension_id())
255       << "Socket has wrong owner.";
256
257   // Don't start another accept if the socket has been paused.
258   if (socket->paused())
259     return;
260
261   socket->Accept(
262       base::Bind(
263           &BluetoothSocketEventDispatcher::AcceptCallback, params),
264       base::Bind(
265           &BluetoothSocketEventDispatcher::AcceptErrorCallback, params));
266 }
267
268 // static
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));
274
275   BluetoothApiSocket* server_api_socket =
276       params.sockets->Get(params.extension_id, params.socket_id);
277   DCHECK(server_api_socket);
278
279   BluetoothApiSocket* client_api_socket = new BluetoothApiSocket(
280       params.extension_id,
281       socket,
282       device->GetAddress(),
283       server_api_socket->uuid());
284   int client_socket_id = params.sockets->Add(client_api_socket);
285
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());
295
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(
299       params.thread_id,
300       FROM_HERE,
301       base::Bind(&BluetoothSocketEventDispatcher::StartAccept, params));
302 }
303
304 // static
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));
310
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
314     // care.
315     return;
316   }
317
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());
329
330   // Since we got an error, the socket is now "paused" until the application
331   // "resumes" it.
332   BluetoothApiSocket* socket =
333       params.sockets->Get(params.extension_id, params.socket_id);
334   if (socket) {
335     socket->set_paused(true);
336   }
337 }
338
339 // static
340 void BluetoothSocketEventDispatcher::PostEvent(const SocketParams& params,
341                                                scoped_ptr<Event> event) {
342   DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
343
344   BrowserThread::PostTask(
345       BrowserThread::UI,
346       FROM_HERE,
347       base::Bind(&DispatchEvent,
348                  params.browser_context_id,
349                  params.extension_id,
350                  base::Passed(event.Pass())));
351 }
352
353 // static
354 void BluetoothSocketEventDispatcher::DispatchEvent(
355     void* browser_context_id,
356     const std::string& extension_id,
357     scoped_ptr<Event> event) {
358   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
359
360   content::BrowserContext* context =
361       reinterpret_cast<content::BrowserContext*>(browser_context_id);
362   if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context))
363     return;
364
365   EventRouter* router = EventRouter::Get(context);
366   if (router)
367     router->DispatchEventToExtension(extension_id, event.Pass());
368 }
369
370 }  // namespace core_api
371 }  // namespace extensions