1c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved. 2c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// found in the LICENSE file. 4c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h" 6c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/lazy_instance.h" 8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "device/bluetooth/bluetooth_device.h" 9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "device/bluetooth/bluetooth_socket.h" 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/api/bluetooth_socket/bluetooth_api_socket.h" 11c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/browser/event_router.h" 121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/common/api/bluetooth_socket.h" 13c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "net/base/io_buffer.h" 14c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 15c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochnamespace { 16c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace bluetooth_socket = extensions::core_api::bluetooth_socket; 18c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochusing extensions::BluetoothApiSocket; 19c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 20c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochint kDefaultBufferSize = 4096; 21c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bluetooth_socket::ReceiveError MapReceiveErrorReason( 235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothApiSocket::ErrorReason value) { 24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch switch (value) { 25c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch case BluetoothApiSocket::kDisconnected: 265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return bluetooth_socket::RECEIVE_ERROR_DISCONNECTED; 275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu case BluetoothApiSocket::kNotConnected: 285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // kNotConnected is impossible since a socket has to be connected to be 295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // able to call Receive() on it. 305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // fallthrough 31c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch case BluetoothApiSocket::kIOPending: 32c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // kIOPending is not relevant to apps, as BluetoothSocketEventDispatcher 33c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // handles this specific error. 34c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // fallthrough 35c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch default: 365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return bluetooth_socket::RECEIVE_ERROR_SYSTEM_ERROR; 37c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 38c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 39c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bluetooth_socket::AcceptError MapAcceptErrorReason( 41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothApiSocket::ErrorReason value) { 42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // TODO(keybuk): All values are system error, we may want to seperate these 43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // out to more discrete reasons. 44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) switch (value) { 45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case BluetoothApiSocket::kNotListening: 46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // kNotListening is impossible since a socket has to be listening to be 47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // able to call Accept() on it. 48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // fallthrough 49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) default: 50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return bluetooth_socket::ACCEPT_ERROR_SYSTEM_ERROR; 51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 54c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} // namespace 55c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 56c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochnamespace extensions { 571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace core_api { 58c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 59c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochusing content::BrowserThread; 60c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liustatic base::LazyInstance< 625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher> > g_factory = 635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu LAZY_INSTANCE_INITIALIZER; 645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static 665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher>* 675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothSocketEventDispatcher::GetFactoryInstance() { 685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return g_factory.Pointer(); 695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static 725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothSocketEventDispatcher* BluetoothSocketEventDispatcher::Get( 735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu content::BrowserContext* context) { 745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK_CURRENTLY_ON(BrowserThread::UI); 755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher>::Get( 775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu context); 785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 80c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochBluetoothSocketEventDispatcher::BluetoothSocketEventDispatcher( 815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu content::BrowserContext* context) 82c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch : thread_id_(BluetoothApiSocket::kThreadId), 835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu browser_context_(context) { 845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ApiResourceManager<BluetoothApiSocket>* manager = 855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ApiResourceManager<BluetoothApiSocket>::Get(browser_context_); 865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(manager) 875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu << "There is no socket manager. " 885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu "If this assertion is failing during a test, then it is likely that " 895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu "TestExtensionSystem is failing to provide an instance of " 905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu "ApiResourceManager<BluetoothApiSocket>."; 915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu sockets_ = manager->data_; 925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 93c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 94c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochBluetoothSocketEventDispatcher::~BluetoothSocketEventDispatcher() {} 95c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)BluetoothSocketEventDispatcher::SocketParams::SocketParams() {} 97c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)BluetoothSocketEventDispatcher::SocketParams::~SocketParams() {} 99c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 100010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void BluetoothSocketEventDispatcher::OnSocketConnect( 101010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const std::string& extension_id, 102010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) int socket_id) { 103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(thread_id_)); 104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SocketParams params; 106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.thread_id = thread_id_; 107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.browser_context_id = browser_context_; 108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.extension_id = extension_id; 109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.sockets = sockets_; 110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.socket_id = socket_id; 111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) StartReceive(params); 113010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 114010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothSocketEventDispatcher::OnSocketListen( 116c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const std::string& extension_id, 117c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int socket_id) { 118c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DCHECK(BrowserThread::CurrentlyOn(thread_id_)); 119c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SocketParams params; 121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.thread_id = thread_id_; 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.browser_context_id = browser_context_; 123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.extension_id = extension_id; 124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.sockets = sockets_; 125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.socket_id = socket_id; 126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) StartAccept(params); 128010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 129010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothSocketEventDispatcher::OnSocketResume( 131010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const std::string& extension_id, 132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) int socket_id) { 133010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(thread_id_)); 134010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SocketParams params; 1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu params.thread_id = thread_id_; 1375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu params.browser_context_id = browser_context_; 138c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch params.extension_id = extension_id; 1395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu params.sockets = sockets_; 140c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch params.socket_id = socket_id; 1415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothApiSocket* socket = 143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.sockets->Get(params.extension_id, params.socket_id); 144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!socket) { 145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // This can happen if the socket is closed while our callback is active. 146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (socket->IsConnected()) { 150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) StartReceive(params); 151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) StartAccept(params); 153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 154c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 155c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 1565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static 157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothSocketEventDispatcher::StartReceive(const SocketParams& params) { 1585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); 159c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 160c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch BluetoothApiSocket* socket = 1615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu params.sockets->Get(params.extension_id, params.socket_id); 162c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!socket) { 163c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // This can happen if the socket is closed while our callback is active. 164c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return; 165c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 166c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DCHECK(params.extension_id == socket->owner_extension_id()) 167c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch << "Socket has wrong owner."; 168c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 169c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Don't start another read if the socket has been paused. 170c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (socket->paused()) 171c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return; 172c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 173c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int buffer_size = socket->buffer_size(); 174c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (buffer_size <= 0) 175c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch buffer_size = kDefaultBufferSize; 176c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch socket->Receive( 177c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch buffer_size, 178c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::Bind( 1795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu &BluetoothSocketEventDispatcher::ReceiveCallback, params), 180c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::Bind( 1815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu &BluetoothSocketEventDispatcher::ReceiveErrorCallback, params)); 182c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 183c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 1845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static 185c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid BluetoothSocketEventDispatcher::ReceiveCallback( 186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const SocketParams& params, 187c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int bytes_read, 188c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch scoped_refptr<net::IOBuffer> io_buffer) { 1895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); 190c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 191c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Dispatch "onReceive" event. 1925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu bluetooth_socket::ReceiveInfo receive_info; 193c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch receive_info.socket_id = params.socket_id; 194c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch receive_info.data = std::string(io_buffer->data(), bytes_read); 1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu scoped_ptr<base::ListValue> args = 1965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu bluetooth_socket::OnReceive::Create(receive_info); 197c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch scoped_ptr<Event> event( 1985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu new Event(bluetooth_socket::OnReceive::kEventName, args.Pass())); 199c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch PostEvent(params, event.Pass()); 200c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 201c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Post a task to delay the read until the socket is available, as 202c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // calling StartReceive at this point would error with ERR_IO_PENDING. 203c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch BrowserThread::PostTask( 2045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu params.thread_id, 205c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch FROM_HERE, 2065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Bind(&BluetoothSocketEventDispatcher::StartReceive, params)); 207c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 208c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 2095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static 210c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid BluetoothSocketEventDispatcher::ReceiveErrorCallback( 211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const SocketParams& params, 212c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch BluetoothApiSocket::ErrorReason error_reason, 213c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const std::string& error) { 2145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); 215c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 216c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (error_reason == BluetoothApiSocket::kIOPending) { 217c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // This happens when resuming a socket which already had an active "read" 218c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // callback. We can safely ignore this error, as the application should not 219c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // care. 220c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return; 221c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 222c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 223c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Dispatch "onReceiveError" event but don't start another read to avoid 224c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // potential infinite reads if we have a persistent network error. 2255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu bluetooth_socket::ReceiveErrorInfo receive_error_info; 226c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch receive_error_info.socket_id = params.socket_id; 227c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch receive_error_info.error_message = error; 228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) receive_error_info.error = MapReceiveErrorReason(error_reason); 229c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch scoped_ptr<base::ListValue> args = 2305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu bluetooth_socket::OnReceiveError::Create(receive_error_info); 231c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch scoped_ptr<Event> event( 2325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu new Event(bluetooth_socket::OnReceiveError::kEventName, args.Pass())); 233c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch PostEvent(params, event.Pass()); 234c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 235c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Since we got an error, the socket is now "paused" until the application 236c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // "resumes" it. 237c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch BluetoothApiSocket* socket = 2385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu params.sockets->Get(params.extension_id, params.socket_id); 239c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (socket) { 240c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch socket->set_paused(true); 241c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 242c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 243c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 2445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static 245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothSocketEventDispatcher::StartAccept(const SocketParams& params) { 246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); 247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothApiSocket* socket = 249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.sockets->Get(params.extension_id, params.socket_id); 250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!socket) { 251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // This can happen if the socket is closed while our callback is active. 252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(params.extension_id == socket->owner_extension_id()) 255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) << "Socket has wrong owner."; 256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Don't start another accept if the socket has been paused. 258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (socket->paused()) 259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) socket->Accept( 262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind( 263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) &BluetoothSocketEventDispatcher::AcceptCallback, params), 264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind( 265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) &BluetoothSocketEventDispatcher::AcceptErrorCallback, params)); 266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static 269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothSocketEventDispatcher::AcceptCallback( 270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const SocketParams& params, 271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const device::BluetoothDevice* device, 272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_refptr<device::BluetoothSocket> socket) { 273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); 274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothApiSocket* server_api_socket = 276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.sockets->Get(params.extension_id, params.socket_id); 277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(server_api_socket); 278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothApiSocket* client_api_socket = new BluetoothApiSocket( 280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.extension_id, 281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) socket, 282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) device->GetAddress(), 283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) server_api_socket->uuid()); 284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int client_socket_id = params.sockets->Add(client_api_socket); 285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Dispatch "onAccept" event. 287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bluetooth_socket::AcceptInfo accept_info; 288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) accept_info.socket_id = params.socket_id; 289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) accept_info.client_socket_id = client_socket_id; 290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<base::ListValue> args = 291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bluetooth_socket::OnAccept::Create(accept_info); 292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<Event> event( 293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) new Event(bluetooth_socket::OnAccept::kEventName, args.Pass())); 294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) PostEvent(params, event.Pass()); 295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Post a task to delay the accept until the socket is available, as 297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // calling StartAccept at this point would error with ERR_IO_PENDING. 298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BrowserThread::PostTask( 299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.thread_id, 300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FROM_HERE, 301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&BluetoothSocketEventDispatcher::StartAccept, params)); 302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static 305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothSocketEventDispatcher::AcceptErrorCallback( 306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const SocketParams& params, 307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothApiSocket::ErrorReason error_reason, 308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& error) { 309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); 310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (error_reason == BluetoothApiSocket::kIOPending) { 312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // This happens when resuming a socket which already had an active "accept" 313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // callback. We can safely ignore this error, as the application should not 314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // care. 315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Dispatch "onAcceptError" event but don't start another accept to avoid 319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // potential infinite accepts if we have a persistent network error. 320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bluetooth_socket::AcceptErrorInfo accept_error_info; 321cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) accept_error_info.socket_id = params.socket_id; 322cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) accept_error_info.error_message = error; 323cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) accept_error_info.error = MapAcceptErrorReason(error_reason); 324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<base::ListValue> args = 325cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bluetooth_socket::OnAcceptError::Create(accept_error_info); 326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<Event> event( 327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) new Event(bluetooth_socket::OnAcceptError::kEventName, args.Pass())); 328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) PostEvent(params, event.Pass()); 329cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Since we got an error, the socket is now "paused" until the application 331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // "resumes" it. 332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothApiSocket* socket = 333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.sockets->Get(params.extension_id, params.socket_id); 334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (socket) { 335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) socket->set_paused(true); 336cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 337cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 338cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static 340cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothSocketEventDispatcher::PostEvent(const SocketParams& params, 341c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch scoped_ptr<Event> event) { 3425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); 343c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 344c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch BrowserThread::PostTask( 345c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch BrowserThread::UI, 346c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch FROM_HERE, 3475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Bind(&DispatchEvent, 3485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu params.browser_context_id, 349c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch params.extension_id, 350c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::Passed(event.Pass()))); 351c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 352c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 3535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static 354c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid BluetoothSocketEventDispatcher::DispatchEvent( 3555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu void* browser_context_id, 356c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const std::string& extension_id, 357c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch scoped_ptr<Event> event) { 358c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 359c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 360c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch content::BrowserContext* context = 3615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu reinterpret_cast<content::BrowserContext*>(browser_context_id); 362c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context)) 363c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return; 364c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 3650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch EventRouter* router = EventRouter::Get(context); 366c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (router) 367c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch router->DispatchEventToExtension(extension_id, event.Pass()); 368c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 369c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 3701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} // namespace core_api 371c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} // namespace extensions 372