| OLD | NEW |
| (Empty) |
| 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_socket/bluetooth_api_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" | |
| 12 #include "extensions/browser/event_router.h" | |
| 13 #include "net/base/io_buffer.h" | |
| 14 #include "net/base/net_errors.h" | |
| 15 | |
| 16 namespace { | |
| 17 | |
| 18 namespace bluetooth_socket = extensions::api::bluetooth_socket; | |
| 19 using extensions::BluetoothApiSocket; | |
| 20 | |
| 21 int kDefaultBufferSize = 4096; | |
| 22 | |
| 23 bluetooth_socket::ReceiveError MapReceiveErrorReason( | |
| 24 BluetoothApiSocket::ErrorReason value) { | |
| 25 switch (value) { | |
| 26 case BluetoothApiSocket::kDisconnected: | |
| 27 return bluetooth_socket::RECEIVE_ERROR_DISCONNECTED; | |
| 28 case BluetoothApiSocket::kNotConnected: | |
| 29 // kNotConnected is impossible since a socket has to be connected to be | |
| 30 // able to call Receive() on it. | |
| 31 // fallthrough | |
| 32 case BluetoothApiSocket::kIOPending: | |
| 33 // kIOPending is not relevant to apps, as BluetoothSocketEventDispatcher | |
| 34 // handles this specific error. | |
| 35 // fallthrough | |
| 36 default: | |
| 37 return bluetooth_socket::RECEIVE_ERROR_SYSTEM_ERROR; | |
| 38 } | |
| 39 } | |
| 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 | |
| 55 } // namespace | |
| 56 | |
| 57 namespace extensions { | |
| 58 namespace api { | |
| 59 | |
| 60 using content::BrowserThread; | |
| 61 | |
| 62 static base::LazyInstance< | |
| 63 BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher> > g_factory = | |
| 64 LAZY_INSTANCE_INITIALIZER; | |
| 65 | |
| 66 // static | |
| 67 BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher>* | |
| 68 BluetoothSocketEventDispatcher::GetFactoryInstance() { | |
| 69 return g_factory.Pointer(); | |
| 70 } | |
| 71 | |
| 72 // static | |
| 73 BluetoothSocketEventDispatcher* BluetoothSocketEventDispatcher::Get( | |
| 74 content::BrowserContext* context) { | |
| 75 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 76 | |
| 77 return BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher>::Get( | |
| 78 context); | |
| 79 } | |
| 80 | |
| 81 BluetoothSocketEventDispatcher::BluetoothSocketEventDispatcher( | |
| 82 content::BrowserContext* context) | |
| 83 : thread_id_(BluetoothApiSocket::kThreadId), | |
| 84 browser_context_(context) { | |
| 85 ApiResourceManager<BluetoothApiSocket>* manager = | |
| 86 ApiResourceManager<BluetoothApiSocket>::Get(browser_context_); | |
| 87 DCHECK(manager) | |
| 88 << "There is no socket manager. " | |
| 89 "If this assertion is failing during a test, then it is likely that " | |
| 90 "TestExtensionSystem is failing to provide an instance of " | |
| 91 "ApiResourceManager<BluetoothApiSocket>."; | |
| 92 sockets_ = manager->data_; | |
| 93 } | |
| 94 | |
| 95 BluetoothSocketEventDispatcher::~BluetoothSocketEventDispatcher() {} | |
| 96 | |
| 97 BluetoothSocketEventDispatcher::SocketParams::SocketParams() {} | |
| 98 | |
| 99 BluetoothSocketEventDispatcher::SocketParams::~SocketParams() {} | |
| 100 | |
| 101 void BluetoothSocketEventDispatcher::OnSocketConnect( | |
| 102 const std::string& extension_id, | |
| 103 int socket_id) { | |
| 104 DCHECK(BrowserThread::CurrentlyOn(thread_id_)); | |
| 105 | |
| 106 SocketParams 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 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 | |
| 157 // static | |
| 158 void BluetoothSocketEventDispatcher::StartReceive(const SocketParams& params) { | |
| 159 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); | |
| 160 | |
| 161 BluetoothApiSocket* socket = | |
| 162 params.sockets->Get(params.extension_id, params.socket_id); | |
| 163 if (!socket) { | |
| 164 // This can happen if the socket is closed while our callback is active. | |
| 165 return; | |
| 166 } | |
| 167 DCHECK(params.extension_id == socket->owner_extension_id()) | |
| 168 << "Socket has wrong owner."; | |
| 169 | |
| 170 // Don't start another read if the socket has been paused. | |
| 171 if (socket->paused()) | |
| 172 return; | |
| 173 | |
| 174 int buffer_size = socket->buffer_size(); | |
| 175 if (buffer_size <= 0) | |
| 176 buffer_size = kDefaultBufferSize; | |
| 177 socket->Receive( | |
| 178 buffer_size, | |
| 179 base::Bind( | |
| 180 &BluetoothSocketEventDispatcher::ReceiveCallback, params), | |
| 181 base::Bind( | |
| 182 &BluetoothSocketEventDispatcher::ReceiveErrorCallback, params)); | |
| 183 } | |
| 184 | |
| 185 // static | |
| 186 void BluetoothSocketEventDispatcher::ReceiveCallback( | |
| 187 const SocketParams& params, | |
| 188 int bytes_read, | |
| 189 scoped_refptr<net::IOBuffer> io_buffer) { | |
| 190 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); | |
| 191 | |
| 192 // Dispatch "onReceive" event. | |
| 193 bluetooth_socket::ReceiveInfo receive_info; | |
| 194 receive_info.socket_id = params.socket_id; | |
| 195 receive_info.data = std::string(io_buffer->data(), bytes_read); | |
| 196 scoped_ptr<base::ListValue> args = | |
| 197 bluetooth_socket::OnReceive::Create(receive_info); | |
| 198 scoped_ptr<Event> event( | |
| 199 new Event(bluetooth_socket::OnReceive::kEventName, args.Pass())); | |
| 200 PostEvent(params, event.Pass()); | |
| 201 | |
| 202 // Post a task to delay the read until the socket is available, as | |
| 203 // calling StartReceive at this point would error with ERR_IO_PENDING. | |
| 204 BrowserThread::PostTask( | |
| 205 params.thread_id, | |
| 206 FROM_HERE, | |
| 207 base::Bind(&BluetoothSocketEventDispatcher::StartReceive, params)); | |
| 208 } | |
| 209 | |
| 210 // static | |
| 211 void BluetoothSocketEventDispatcher::ReceiveErrorCallback( | |
| 212 const SocketParams& params, | |
| 213 BluetoothApiSocket::ErrorReason error_reason, | |
| 214 const std::string& error) { | |
| 215 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); | |
| 216 | |
| 217 if (error_reason == BluetoothApiSocket::kIOPending) { | |
| 218 // This happens when resuming a socket which already had an active "read" | |
| 219 // callback. We can safely ignore this error, as the application should not | |
| 220 // care. | |
| 221 return; | |
| 222 } | |
| 223 | |
| 224 // Dispatch "onReceiveError" event but don't start another read to avoid | |
| 225 // potential infinite reads if we have a persistent network error. | |
| 226 bluetooth_socket::ReceiveErrorInfo receive_error_info; | |
| 227 receive_error_info.socket_id = params.socket_id; | |
| 228 receive_error_info.error_message = error; | |
| 229 receive_error_info.error = MapReceiveErrorReason(error_reason); | |
| 230 scoped_ptr<base::ListValue> args = | |
| 231 bluetooth_socket::OnReceiveError::Create(receive_error_info); | |
| 232 scoped_ptr<Event> event( | |
| 233 new Event(bluetooth_socket::OnReceiveError::kEventName, args.Pass())); | |
| 234 PostEvent(params, event.Pass()); | |
| 235 | |
| 236 // Since we got an error, the socket is now "paused" until the application | |
| 237 // "resumes" it. | |
| 238 BluetoothApiSocket* socket = | |
| 239 params.sockets->Get(params.extension_id, params.socket_id); | |
| 240 if (socket) { | |
| 241 socket->set_paused(true); | |
| 242 } | |
| 243 } | |
| 244 | |
| 245 // static | |
| 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, | |
| 342 scoped_ptr<Event> event) { | |
| 343 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); | |
| 344 | |
| 345 BrowserThread::PostTask( | |
| 346 BrowserThread::UI, | |
| 347 FROM_HERE, | |
| 348 base::Bind(&DispatchEvent, | |
| 349 params.browser_context_id, | |
| 350 params.extension_id, | |
| 351 base::Passed(event.Pass()))); | |
| 352 } | |
| 353 | |
| 354 // static | |
| 355 void BluetoothSocketEventDispatcher::DispatchEvent( | |
| 356 void* browser_context_id, | |
| 357 const std::string& extension_id, | |
| 358 scoped_ptr<Event> event) { | |
| 359 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 360 | |
| 361 content::BrowserContext* context = | |
| 362 reinterpret_cast<content::BrowserContext*>(browser_context_id); | |
| 363 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context)) | |
| 364 return; | |
| 365 | |
| 366 EventRouter* router = EventRouter::Get(context); | |
| 367 if (router) | |
| 368 router->DispatchEventToExtension(extension_id, event.Pass()); | |
| 369 } | |
| 370 | |
| 371 } // namespace api | |
| 372 } // namespace extensions | |
| OLD | NEW |