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 "chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h"
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"
16 namespace bluetooth_socket = extensions::api::bluetooth_socket;
17 using extensions::BluetoothApiSocket;
19 int kDefaultBufferSize = 4096;
21 bluetooth_socket::ReceiveError MapErrorReason(
22 BluetoothApiSocket::ErrorReason 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.
30 case BluetoothApiSocket::kIOPending:
31 // kIOPending is not relevant to apps, as BluetoothSocketEventDispatcher
32 // handles this specific error.
35 return bluetooth_socket::RECEIVE_ERROR_SYSTEM_ERROR;
41 namespace extensions {
44 using content::BrowserThread;
46 static base::LazyInstance<
47 BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher> > g_factory =
48 LAZY_INSTANCE_INITIALIZER;
51 BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher>*
52 BluetoothSocketEventDispatcher::GetFactoryInstance() {
53 return g_factory.Pointer();
57 BluetoothSocketEventDispatcher* BluetoothSocketEventDispatcher::Get(
58 content::BrowserContext* context) {
59 DCHECK_CURRENTLY_ON(BrowserThread::UI);
61 return BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher>::Get(
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_);
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_;
79 BluetoothSocketEventDispatcher::~BluetoothSocketEventDispatcher() {}
81 BluetoothSocketEventDispatcher::ReceiveParams::ReceiveParams() {}
83 BluetoothSocketEventDispatcher::ReceiveParams::~ReceiveParams() {}
85 void BluetoothSocketEventDispatcher::OnSocketConnect(
86 const std::string& extension_id,
88 DCHECK(BrowserThread::CurrentlyOn(thread_id_));
90 StartSocketReceive(extension_id, socket_id);
93 void BluetoothSocketEventDispatcher::OnSocketResume(
94 const std::string& extension_id,
96 DCHECK(BrowserThread::CurrentlyOn(thread_id_));
98 StartSocketReceive(extension_id, socket_id);
101 void BluetoothSocketEventDispatcher::StartSocketReceive(
102 const std::string& extension_id,
104 DCHECK(BrowserThread::CurrentlyOn(thread_id_));
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;
113 StartReceive(params);
117 void BluetoothSocketEventDispatcher::StartReceive(const ReceiveParams& params) {
118 DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
120 BluetoothApiSocket* socket =
121 params.sockets->Get(params.extension_id, params.socket_id);
123 // This can happen if the socket is closed while our callback is active.
126 DCHECK(params.extension_id == socket->owner_extension_id())
127 << "Socket has wrong owner.";
129 // Don't start another read if the socket has been paused.
130 if (socket->paused())
133 int buffer_size = socket->buffer_size();
134 if (buffer_size <= 0)
135 buffer_size = kDefaultBufferSize;
139 &BluetoothSocketEventDispatcher::ReceiveCallback, params),
141 &BluetoothSocketEventDispatcher::ReceiveErrorCallback, params));
145 void BluetoothSocketEventDispatcher::ReceiveCallback(
146 const ReceiveParams& params,
148 scoped_refptr<net::IOBuffer> io_buffer) {
149 DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
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());
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(
166 base::Bind(&BluetoothSocketEventDispatcher::StartReceive, params));
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));
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
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());
195 // Since we got an error, the socket is now "paused" until the application
197 BluetoothApiSocket* socket =
198 params.sockets->Get(params.extension_id, params.socket_id);
200 socket->set_paused(true);
205 void BluetoothSocketEventDispatcher::PostEvent(const ReceiveParams& params,
206 scoped_ptr<Event> event) {
207 DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
209 BrowserThread::PostTask(
212 base::Bind(&DispatchEvent,
213 params.browser_context_id,
215 base::Passed(event.Pass())));
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));
225 content::BrowserContext* context =
226 reinterpret_cast<content::BrowserContext*>(browser_context_id);
227 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context))
230 EventRouter* router = EventRouter::Get(context);
232 router->DispatchEventToExtension(extension_id, event.Pass());
236 } // namespace extensions