OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_event_
dispatcher.h" | 5 #include "chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_event_
dispatcher.h" |
6 | 6 |
7 #include "chrome/browser/browser_process.h" | 7 #include "chrome/browser/browser_process.h" |
8 #include "chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.h" | 8 #include "chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.h" |
9 #include "chrome/common/extensions/api/bluetooth_socket.h" | 9 #include "chrome/common/extensions/api/bluetooth_socket.h" |
| 10 #include "device/bluetooth/bluetooth_device.h" |
| 11 #include "device/bluetooth/bluetooth_socket.h" |
10 #include "extensions/browser/event_router.h" | 12 #include "extensions/browser/event_router.h" |
11 #include "net/base/io_buffer.h" | 13 #include "net/base/io_buffer.h" |
12 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
13 | 15 |
14 namespace { | 16 namespace { |
15 | 17 |
16 namespace bluetooth_socket = extensions::api::bluetooth_socket; | 18 namespace bluetooth_socket = extensions::api::bluetooth_socket; |
17 using extensions::BluetoothApiSocket; | 19 using extensions::BluetoothApiSocket; |
18 | 20 |
19 int kDefaultBufferSize = 4096; | 21 int kDefaultBufferSize = 4096; |
20 | 22 |
21 bluetooth_socket::ReceiveError MapErrorReason( | 23 bluetooth_socket::ReceiveError MapReceiveErrorReason( |
22 BluetoothApiSocket::ErrorReason value) { | 24 BluetoothApiSocket::ErrorReason value) { |
23 switch (value) { | 25 switch (value) { |
24 case BluetoothApiSocket::kDisconnected: | 26 case BluetoothApiSocket::kDisconnected: |
25 return bluetooth_socket::RECEIVE_ERROR_DISCONNECTED; | 27 return bluetooth_socket::RECEIVE_ERROR_DISCONNECTED; |
26 case BluetoothApiSocket::kNotConnected: | 28 case BluetoothApiSocket::kNotConnected: |
27 // kNotConnected is impossible since a socket has to be connected to be | 29 // kNotConnected is impossible since a socket has to be connected to be |
28 // able to call Receive() on it. | 30 // able to call Receive() on it. |
29 // fallthrough | 31 // fallthrough |
30 case BluetoothApiSocket::kIOPending: | 32 case BluetoothApiSocket::kIOPending: |
31 // kIOPending is not relevant to apps, as BluetoothSocketEventDispatcher | 33 // kIOPending is not relevant to apps, as BluetoothSocketEventDispatcher |
32 // handles this specific error. | 34 // handles this specific error. |
33 // fallthrough | 35 // fallthrough |
34 default: | 36 default: |
35 return bluetooth_socket::RECEIVE_ERROR_SYSTEM_ERROR; | 37 return bluetooth_socket::RECEIVE_ERROR_SYSTEM_ERROR; |
36 } | 38 } |
37 } | 39 } |
38 | 40 |
| 41 bluetooth_socket::AcceptError MapAcceptErrorReason( |
| 42 BluetoothApiSocket::ErrorReason value) { |
| 43 // TODO(keybuk): All values are system error, we may want to seperate these |
| 44 // out to more discrete reasons. |
| 45 switch (value) { |
| 46 case BluetoothApiSocket::kNotListening: |
| 47 // kNotListening is impossible since a socket has to be listening to be |
| 48 // able to call Accept() on it. |
| 49 // fallthrough |
| 50 default: |
| 51 return bluetooth_socket::ACCEPT_ERROR_SYSTEM_ERROR; |
| 52 } |
| 53 } |
| 54 |
39 } // namespace | 55 } // namespace |
40 | 56 |
41 namespace extensions { | 57 namespace extensions { |
42 namespace api { | 58 namespace api { |
43 | 59 |
44 using content::BrowserThread; | 60 using content::BrowserThread; |
45 | 61 |
46 static base::LazyInstance< | 62 static base::LazyInstance< |
47 BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher> > g_factory = | 63 BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher> > g_factory = |
48 LAZY_INSTANCE_INITIALIZER; | 64 LAZY_INSTANCE_INITIALIZER; |
(...skipping 22 matching lines...) Expand all Loading... |
71 DCHECK(manager) | 87 DCHECK(manager) |
72 << "There is no socket manager. " | 88 << "There is no socket manager. " |
73 "If this assertion is failing during a test, then it is likely that " | 89 "If this assertion is failing during a test, then it is likely that " |
74 "TestExtensionSystem is failing to provide an instance of " | 90 "TestExtensionSystem is failing to provide an instance of " |
75 "ApiResourceManager<BluetoothApiSocket>."; | 91 "ApiResourceManager<BluetoothApiSocket>."; |
76 sockets_ = manager->data_; | 92 sockets_ = manager->data_; |
77 } | 93 } |
78 | 94 |
79 BluetoothSocketEventDispatcher::~BluetoothSocketEventDispatcher() {} | 95 BluetoothSocketEventDispatcher::~BluetoothSocketEventDispatcher() {} |
80 | 96 |
81 BluetoothSocketEventDispatcher::ReceiveParams::ReceiveParams() {} | 97 BluetoothSocketEventDispatcher::SocketParams::SocketParams() {} |
82 | 98 |
83 BluetoothSocketEventDispatcher::ReceiveParams::~ReceiveParams() {} | 99 BluetoothSocketEventDispatcher::SocketParams::~SocketParams() {} |
84 | 100 |
85 void BluetoothSocketEventDispatcher::OnSocketConnect( | 101 void BluetoothSocketEventDispatcher::OnSocketConnect( |
86 const std::string& extension_id, | 102 const std::string& extension_id, |
87 int socket_id) { | 103 int socket_id) { |
88 DCHECK(BrowserThread::CurrentlyOn(thread_id_)); | 104 DCHECK(BrowserThread::CurrentlyOn(thread_id_)); |
89 | 105 |
90 StartSocketReceive(extension_id, socket_id); | 106 SocketParams params; |
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_; | 107 params.thread_id = thread_id_; |
108 params.browser_context_id = browser_context_; | 108 params.browser_context_id = browser_context_; |
109 params.extension_id = extension_id; | 109 params.extension_id = extension_id; |
110 params.sockets = sockets_; | 110 params.sockets = sockets_; |
111 params.socket_id = socket_id; | 111 params.socket_id = socket_id; |
112 | 112 |
113 StartReceive(params); | 113 StartReceive(params); |
114 } | 114 } |
115 | 115 |
| 116 void BluetoothSocketEventDispatcher::OnSocketListen( |
| 117 const std::string& extension_id, |
| 118 int socket_id) { |
| 119 DCHECK(BrowserThread::CurrentlyOn(thread_id_)); |
| 120 |
| 121 SocketParams params; |
| 122 params.thread_id = thread_id_; |
| 123 params.browser_context_id = browser_context_; |
| 124 params.extension_id = extension_id; |
| 125 params.sockets = sockets_; |
| 126 params.socket_id = socket_id; |
| 127 |
| 128 StartAccept(params); |
| 129 } |
| 130 |
| 131 void BluetoothSocketEventDispatcher::OnSocketResume( |
| 132 const std::string& extension_id, |
| 133 int socket_id) { |
| 134 DCHECK(BrowserThread::CurrentlyOn(thread_id_)); |
| 135 |
| 136 SocketParams params; |
| 137 params.thread_id = thread_id_; |
| 138 params.browser_context_id = browser_context_; |
| 139 params.extension_id = extension_id; |
| 140 params.sockets = sockets_; |
| 141 params.socket_id = socket_id; |
| 142 |
| 143 BluetoothApiSocket* socket = |
| 144 params.sockets->Get(params.extension_id, params.socket_id); |
| 145 if (!socket) { |
| 146 // This can happen if the socket is closed while our callback is active. |
| 147 return; |
| 148 } |
| 149 |
| 150 if (socket->IsConnected()) { |
| 151 StartReceive(params); |
| 152 } else { |
| 153 StartAccept(params); |
| 154 } |
| 155 } |
| 156 |
116 // static | 157 // static |
117 void BluetoothSocketEventDispatcher::StartReceive(const ReceiveParams& params) { | 158 void BluetoothSocketEventDispatcher::StartReceive(const SocketParams& params) { |
118 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); | 159 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); |
119 | 160 |
120 BluetoothApiSocket* socket = | 161 BluetoothApiSocket* socket = |
121 params.sockets->Get(params.extension_id, params.socket_id); | 162 params.sockets->Get(params.extension_id, params.socket_id); |
122 if (!socket) { | 163 if (!socket) { |
123 // This can happen if the socket is closed while our callback is active. | 164 // This can happen if the socket is closed while our callback is active. |
124 return; | 165 return; |
125 } | 166 } |
126 DCHECK(params.extension_id == socket->owner_extension_id()) | 167 DCHECK(params.extension_id == socket->owner_extension_id()) |
127 << "Socket has wrong owner."; | 168 << "Socket has wrong owner."; |
128 | 169 |
129 // Don't start another read if the socket has been paused. | 170 // Don't start another read if the socket has been paused. |
130 if (socket->paused()) | 171 if (socket->paused()) |
131 return; | 172 return; |
132 | 173 |
133 int buffer_size = socket->buffer_size(); | 174 int buffer_size = socket->buffer_size(); |
134 if (buffer_size <= 0) | 175 if (buffer_size <= 0) |
135 buffer_size = kDefaultBufferSize; | 176 buffer_size = kDefaultBufferSize; |
136 socket->Receive( | 177 socket->Receive( |
137 buffer_size, | 178 buffer_size, |
138 base::Bind( | 179 base::Bind( |
139 &BluetoothSocketEventDispatcher::ReceiveCallback, params), | 180 &BluetoothSocketEventDispatcher::ReceiveCallback, params), |
140 base::Bind( | 181 base::Bind( |
141 &BluetoothSocketEventDispatcher::ReceiveErrorCallback, params)); | 182 &BluetoothSocketEventDispatcher::ReceiveErrorCallback, params)); |
142 } | 183 } |
143 | 184 |
144 // static | 185 // static |
145 void BluetoothSocketEventDispatcher::ReceiveCallback( | 186 void BluetoothSocketEventDispatcher::ReceiveCallback( |
146 const ReceiveParams& params, | 187 const SocketParams& params, |
147 int bytes_read, | 188 int bytes_read, |
148 scoped_refptr<net::IOBuffer> io_buffer) { | 189 scoped_refptr<net::IOBuffer> io_buffer) { |
149 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); | 190 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); |
150 | 191 |
151 // Dispatch "onReceive" event. | 192 // Dispatch "onReceive" event. |
152 bluetooth_socket::ReceiveInfo receive_info; | 193 bluetooth_socket::ReceiveInfo receive_info; |
153 receive_info.socket_id = params.socket_id; | 194 receive_info.socket_id = params.socket_id; |
154 receive_info.data = std::string(io_buffer->data(), bytes_read); | 195 receive_info.data = std::string(io_buffer->data(), bytes_read); |
155 scoped_ptr<base::ListValue> args = | 196 scoped_ptr<base::ListValue> args = |
156 bluetooth_socket::OnReceive::Create(receive_info); | 197 bluetooth_socket::OnReceive::Create(receive_info); |
157 scoped_ptr<Event> event( | 198 scoped_ptr<Event> event( |
158 new Event(bluetooth_socket::OnReceive::kEventName, args.Pass())); | 199 new Event(bluetooth_socket::OnReceive::kEventName, args.Pass())); |
159 PostEvent(params, event.Pass()); | 200 PostEvent(params, event.Pass()); |
160 | 201 |
161 // Post a task to delay the read until the socket is available, as | 202 // 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. | 203 // calling StartReceive at this point would error with ERR_IO_PENDING. |
163 BrowserThread::PostTask( | 204 BrowserThread::PostTask( |
164 params.thread_id, | 205 params.thread_id, |
165 FROM_HERE, | 206 FROM_HERE, |
166 base::Bind(&BluetoothSocketEventDispatcher::StartReceive, params)); | 207 base::Bind(&BluetoothSocketEventDispatcher::StartReceive, params)); |
167 } | 208 } |
168 | 209 |
169 // static | 210 // static |
170 void BluetoothSocketEventDispatcher::ReceiveErrorCallback( | 211 void BluetoothSocketEventDispatcher::ReceiveErrorCallback( |
171 const ReceiveParams& params, | 212 const SocketParams& params, |
172 BluetoothApiSocket::ErrorReason error_reason, | 213 BluetoothApiSocket::ErrorReason error_reason, |
173 const std::string& error) { | 214 const std::string& error) { |
174 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); | 215 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); |
175 | 216 |
176 if (error_reason == BluetoothApiSocket::kIOPending) { | 217 if (error_reason == BluetoothApiSocket::kIOPending) { |
177 // This happens when resuming a socket which already had an active "read" | 218 // 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 | 219 // callback. We can safely ignore this error, as the application should not |
179 // care. | 220 // care. |
180 return; | 221 return; |
181 } | 222 } |
182 | 223 |
183 // Dispatch "onReceiveError" event but don't start another read to avoid | 224 // Dispatch "onReceiveError" event but don't start another read to avoid |
184 // potential infinite reads if we have a persistent network error. | 225 // potential infinite reads if we have a persistent network error. |
185 bluetooth_socket::ReceiveErrorInfo receive_error_info; | 226 bluetooth_socket::ReceiveErrorInfo receive_error_info; |
186 receive_error_info.socket_id = params.socket_id; | 227 receive_error_info.socket_id = params.socket_id; |
187 receive_error_info.error_message = error; | 228 receive_error_info.error_message = error; |
188 receive_error_info.error = MapErrorReason(error_reason); | 229 receive_error_info.error = MapReceiveErrorReason(error_reason); |
189 scoped_ptr<base::ListValue> args = | 230 scoped_ptr<base::ListValue> args = |
190 bluetooth_socket::OnReceiveError::Create(receive_error_info); | 231 bluetooth_socket::OnReceiveError::Create(receive_error_info); |
191 scoped_ptr<Event> event( | 232 scoped_ptr<Event> event( |
192 new Event(bluetooth_socket::OnReceiveError::kEventName, args.Pass())); | 233 new Event(bluetooth_socket::OnReceiveError::kEventName, args.Pass())); |
193 PostEvent(params, event.Pass()); | 234 PostEvent(params, event.Pass()); |
194 | 235 |
195 // Since we got an error, the socket is now "paused" until the application | 236 // Since we got an error, the socket is now "paused" until the application |
196 // "resumes" it. | 237 // "resumes" it. |
197 BluetoothApiSocket* socket = | 238 BluetoothApiSocket* socket = |
198 params.sockets->Get(params.extension_id, params.socket_id); | 239 params.sockets->Get(params.extension_id, params.socket_id); |
199 if (socket) { | 240 if (socket) { |
200 socket->set_paused(true); | 241 socket->set_paused(true); |
201 } | 242 } |
202 } | 243 } |
203 | 244 |
204 // static | 245 // static |
205 void BluetoothSocketEventDispatcher::PostEvent(const ReceiveParams& params, | 246 void BluetoothSocketEventDispatcher::StartAccept(const SocketParams& params) { |
| 247 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); |
| 248 |
| 249 BluetoothApiSocket* socket = |
| 250 params.sockets->Get(params.extension_id, params.socket_id); |
| 251 if (!socket) { |
| 252 // This can happen if the socket is closed while our callback is active. |
| 253 return; |
| 254 } |
| 255 DCHECK(params.extension_id == socket->owner_extension_id()) |
| 256 << "Socket has wrong owner."; |
| 257 |
| 258 // Don't start another accept if the socket has been paused. |
| 259 if (socket->paused()) |
| 260 return; |
| 261 |
| 262 socket->Accept( |
| 263 base::Bind( |
| 264 &BluetoothSocketEventDispatcher::AcceptCallback, params), |
| 265 base::Bind( |
| 266 &BluetoothSocketEventDispatcher::AcceptErrorCallback, params)); |
| 267 } |
| 268 |
| 269 // static |
| 270 void BluetoothSocketEventDispatcher::AcceptCallback( |
| 271 const SocketParams& params, |
| 272 const device::BluetoothDevice* device, |
| 273 scoped_refptr<device::BluetoothSocket> socket) { |
| 274 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); |
| 275 |
| 276 BluetoothApiSocket* server_api_socket = |
| 277 params.sockets->Get(params.extension_id, params.socket_id); |
| 278 DCHECK(server_api_socket); |
| 279 |
| 280 BluetoothApiSocket* client_api_socket = new BluetoothApiSocket( |
| 281 params.extension_id, |
| 282 socket, |
| 283 device->GetAddress(), |
| 284 server_api_socket->uuid()); |
| 285 int client_socket_id = params.sockets->Add(client_api_socket); |
| 286 |
| 287 // Dispatch "onAccept" event. |
| 288 bluetooth_socket::AcceptInfo accept_info; |
| 289 accept_info.socket_id = params.socket_id; |
| 290 accept_info.client_socket_id = client_socket_id; |
| 291 scoped_ptr<base::ListValue> args = |
| 292 bluetooth_socket::OnAccept::Create(accept_info); |
| 293 scoped_ptr<Event> event( |
| 294 new Event(bluetooth_socket::OnAccept::kEventName, args.Pass())); |
| 295 PostEvent(params, event.Pass()); |
| 296 |
| 297 // Post a task to delay the accept until the socket is available, as |
| 298 // calling StartAccept at this point would error with ERR_IO_PENDING. |
| 299 BrowserThread::PostTask( |
| 300 params.thread_id, |
| 301 FROM_HERE, |
| 302 base::Bind(&BluetoothSocketEventDispatcher::StartAccept, params)); |
| 303 } |
| 304 |
| 305 // static |
| 306 void BluetoothSocketEventDispatcher::AcceptErrorCallback( |
| 307 const SocketParams& params, |
| 308 BluetoothApiSocket::ErrorReason error_reason, |
| 309 const std::string& error) { |
| 310 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); |
| 311 |
| 312 if (error_reason == BluetoothApiSocket::kIOPending) { |
| 313 // This happens when resuming a socket which already had an active "accept" |
| 314 // callback. We can safely ignore this error, as the application should not |
| 315 // care. |
| 316 return; |
| 317 } |
| 318 |
| 319 // Dispatch "onAcceptError" event but don't start another accept to avoid |
| 320 // potential infinite accepts if we have a persistent network error. |
| 321 bluetooth_socket::AcceptErrorInfo accept_error_info; |
| 322 accept_error_info.socket_id = params.socket_id; |
| 323 accept_error_info.error_message = error; |
| 324 accept_error_info.error = MapAcceptErrorReason(error_reason); |
| 325 scoped_ptr<base::ListValue> args = |
| 326 bluetooth_socket::OnAcceptError::Create(accept_error_info); |
| 327 scoped_ptr<Event> event( |
| 328 new Event(bluetooth_socket::OnAcceptError::kEventName, args.Pass())); |
| 329 PostEvent(params, event.Pass()); |
| 330 |
| 331 // Since we got an error, the socket is now "paused" until the application |
| 332 // "resumes" it. |
| 333 BluetoothApiSocket* socket = |
| 334 params.sockets->Get(params.extension_id, params.socket_id); |
| 335 if (socket) { |
| 336 socket->set_paused(true); |
| 337 } |
| 338 } |
| 339 |
| 340 // static |
| 341 void BluetoothSocketEventDispatcher::PostEvent(const SocketParams& params, |
206 scoped_ptr<Event> event) { | 342 scoped_ptr<Event> event) { |
207 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); | 343 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); |
208 | 344 |
209 BrowserThread::PostTask( | 345 BrowserThread::PostTask( |
210 BrowserThread::UI, | 346 BrowserThread::UI, |
211 FROM_HERE, | 347 FROM_HERE, |
212 base::Bind(&DispatchEvent, | 348 base::Bind(&DispatchEvent, |
213 params.browser_context_id, | 349 params.browser_context_id, |
214 params.extension_id, | 350 params.extension_id, |
215 base::Passed(event.Pass()))); | 351 base::Passed(event.Pass()))); |
(...skipping 11 matching lines...) Expand all Loading... |
227 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context)) | 363 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context)) |
228 return; | 364 return; |
229 | 365 |
230 EventRouter* router = EventRouter::Get(context); | 366 EventRouter* router = EventRouter::Get(context); |
231 if (router) | 367 if (router) |
232 router->DispatchEventToExtension(extension_id, event.Pass()); | 368 router->DispatchEventToExtension(extension_id, event.Pass()); |
233 } | 369 } |
234 | 370 |
235 } // namespace api | 371 } // namespace api |
236 } // namespace extensions | 372 } // namespace extensions |
OLD | NEW |