Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / 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 "chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h"
6
7 #include "chrome/browser/browser_process.h"
8 #include "chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.h"
9 #include "chrome/common/extensions/api/bluetooth_socket.h"
10 #include "extensions/browser/event_router.h"
11 #include "net/base/io_buffer.h"
12 #include "net/base/net_errors.h"
13
14 namespace {
15
16 namespace bluetooth_socket = extensions::api::bluetooth_socket;
17 using extensions::BluetoothApiSocket;
18
19 int kDefaultBufferSize = 4096;
20
21 bluetooth_socket::ReceiveError MapErrorReason(
22     BluetoothApiSocket::ErrorReason value) {
23   switch (value) {
24     case BluetoothApiSocket::kDisconnected:
25       return bluetooth_socket::RECEIVE_ERROR_DISCONNECTED;
26     case BluetoothApiSocket::kNotConnected:
27     // kNotConnected is impossible since a socket has to be connected to be
28     // able to call Receive() on it.
29     // fallthrough
30     case BluetoothApiSocket::kIOPending:
31     // kIOPending is not relevant to apps, as BluetoothSocketEventDispatcher
32     // handles this specific error.
33     // fallthrough
34     default:
35       return bluetooth_socket::RECEIVE_ERROR_SYSTEM_ERROR;
36   }
37 }
38
39 }  // namespace
40
41 namespace extensions {
42 namespace api {
43
44 using content::BrowserThread;
45
46 static base::LazyInstance<
47     BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher> > g_factory =
48     LAZY_INSTANCE_INITIALIZER;
49
50 // static
51 BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher>*
52 BluetoothSocketEventDispatcher::GetFactoryInstance() {
53   return g_factory.Pointer();
54 }
55
56 // static
57 BluetoothSocketEventDispatcher* BluetoothSocketEventDispatcher::Get(
58     content::BrowserContext* context) {
59   DCHECK_CURRENTLY_ON(BrowserThread::UI);
60
61   return BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher>::Get(
62       context);
63 }
64
65 BluetoothSocketEventDispatcher::BluetoothSocketEventDispatcher(
66     content::BrowserContext* context)
67     : thread_id_(BluetoothApiSocket::kThreadId),
68       browser_context_(context) {
69   ApiResourceManager<BluetoothApiSocket>* manager =
70       ApiResourceManager<BluetoothApiSocket>::Get(browser_context_);
71   DCHECK(manager)
72       << "There is no socket manager. "
73          "If this assertion is failing during a test, then it is likely that "
74          "TestExtensionSystem is failing to provide an instance of "
75          "ApiResourceManager<BluetoothApiSocket>.";
76   sockets_ = manager->data_;
77 }
78
79 BluetoothSocketEventDispatcher::~BluetoothSocketEventDispatcher() {}
80
81 BluetoothSocketEventDispatcher::ReceiveParams::ReceiveParams() {}
82
83 BluetoothSocketEventDispatcher::ReceiveParams::~ReceiveParams() {}
84
85 void BluetoothSocketEventDispatcher::OnSocketConnect(
86     const std::string& extension_id,
87     int socket_id) {
88   DCHECK(BrowserThread::CurrentlyOn(thread_id_));
89
90   StartSocketReceive(extension_id, socket_id);
91 }
92
93 void BluetoothSocketEventDispatcher::OnSocketResume(
94     const std::string& extension_id,
95     int socket_id) {
96   DCHECK(BrowserThread::CurrentlyOn(thread_id_));
97
98   StartSocketReceive(extension_id, socket_id);
99 }
100
101 void BluetoothSocketEventDispatcher::StartSocketReceive(
102     const std::string& extension_id,
103     int socket_id) {
104   DCHECK(BrowserThread::CurrentlyOn(thread_id_));
105
106   ReceiveParams params;
107   params.thread_id = thread_id_;
108   params.browser_context_id = browser_context_;
109   params.extension_id = extension_id;
110   params.sockets = sockets_;
111   params.socket_id = socket_id;
112
113   StartReceive(params);
114 }
115
116 // static
117 void BluetoothSocketEventDispatcher::StartReceive(const ReceiveParams& params) {
118   DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
119
120   BluetoothApiSocket* socket =
121       params.sockets->Get(params.extension_id, params.socket_id);
122   if (!socket) {
123     // This can happen if the socket is closed while our callback is active.
124     return;
125   }
126   DCHECK(params.extension_id == socket->owner_extension_id())
127       << "Socket has wrong owner.";
128
129   // Don't start another read if the socket has been paused.
130   if (socket->paused())
131     return;
132
133   int buffer_size = socket->buffer_size();
134   if (buffer_size <= 0)
135     buffer_size = kDefaultBufferSize;
136   socket->Receive(
137       buffer_size,
138       base::Bind(
139           &BluetoothSocketEventDispatcher::ReceiveCallback, params),
140       base::Bind(
141           &BluetoothSocketEventDispatcher::ReceiveErrorCallback, params));
142 }
143
144 // static
145 void BluetoothSocketEventDispatcher::ReceiveCallback(
146     const ReceiveParams& params,
147     int bytes_read,
148     scoped_refptr<net::IOBuffer> io_buffer) {
149   DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
150
151   // Dispatch "onReceive" event.
152   bluetooth_socket::ReceiveInfo receive_info;
153   receive_info.socket_id = params.socket_id;
154   receive_info.data = std::string(io_buffer->data(), bytes_read);
155   scoped_ptr<base::ListValue> args =
156       bluetooth_socket::OnReceive::Create(receive_info);
157   scoped_ptr<Event> event(
158       new Event(bluetooth_socket::OnReceive::kEventName, args.Pass()));
159   PostEvent(params, event.Pass());
160
161   // Post a task to delay the read until the socket is available, as
162   // calling StartReceive at this point would error with ERR_IO_PENDING.
163   BrowserThread::PostTask(
164       params.thread_id,
165       FROM_HERE,
166       base::Bind(&BluetoothSocketEventDispatcher::StartReceive, params));
167 }
168
169 // static
170 void BluetoothSocketEventDispatcher::ReceiveErrorCallback(
171     const ReceiveParams& params,
172     BluetoothApiSocket::ErrorReason error_reason,
173     const std::string& error) {
174   DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
175
176   if (error_reason == BluetoothApiSocket::kIOPending) {
177     // This happens when resuming a socket which already had an active "read"
178     // callback. We can safely ignore this error, as the application should not
179     // care.
180     return;
181   }
182
183   // Dispatch "onReceiveError" event but don't start another read to avoid
184   // potential infinite reads if we have a persistent network error.
185   bluetooth_socket::ReceiveErrorInfo receive_error_info;
186   receive_error_info.socket_id = params.socket_id;
187   receive_error_info.error_message = error;
188   receive_error_info.error = MapErrorReason(error_reason);
189   scoped_ptr<base::ListValue> args =
190       bluetooth_socket::OnReceiveError::Create(receive_error_info);
191   scoped_ptr<Event> event(
192       new Event(bluetooth_socket::OnReceiveError::kEventName, args.Pass()));
193   PostEvent(params, event.Pass());
194
195   // Since we got an error, the socket is now "paused" until the application
196   // "resumes" it.
197   BluetoothApiSocket* socket =
198       params.sockets->Get(params.extension_id, params.socket_id);
199   if (socket) {
200     socket->set_paused(true);
201   }
202 }
203
204 // static
205 void BluetoothSocketEventDispatcher::PostEvent(const ReceiveParams& params,
206                                                scoped_ptr<Event> event) {
207   DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
208
209   BrowserThread::PostTask(
210       BrowserThread::UI,
211       FROM_HERE,
212       base::Bind(&DispatchEvent,
213                  params.browser_context_id,
214                  params.extension_id,
215                  base::Passed(event.Pass())));
216 }
217
218 // static
219 void BluetoothSocketEventDispatcher::DispatchEvent(
220     void* browser_context_id,
221     const std::string& extension_id,
222     scoped_ptr<Event> event) {
223   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
224
225   content::BrowserContext* context =
226       reinterpret_cast<content::BrowserContext*>(browser_context_id);
227   if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context))
228     return;
229
230   EventRouter* router = EventRouter::Get(context);
231   if (router)
232     router->DispatchEventToExtension(extension_id, event.Pass());
233 }
234
235 }  // namespace api
236 }  // namespace extensions