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 372