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_api_socket.h" 6c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/lazy_instance.h" 8c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "device/bluetooth/bluetooth_socket.h" 9c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "net/base/io_buffer.h" 10c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liunamespace { 125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst char kSocketNotConnectedError[] = "Socket not connected"; 14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kSocketNotListeningError[] = "Socket not listening"; 155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} // namespace 175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 18c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochnamespace extensions { 19c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 20c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// static 21c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochstatic base::LazyInstance< 22c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch BrowserContextKeyedAPIFactory<ApiResourceManager<BluetoothApiSocket> > > 23c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch g_server_factory = LAZY_INSTANCE_INITIALIZER; 24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 25c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// static 26c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochtemplate <> 27c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochBrowserContextKeyedAPIFactory<ApiResourceManager<BluetoothApiSocket> >* 28c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochApiResourceManager<BluetoothApiSocket>::GetFactoryInstance() { 29c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return g_server_factory.Pointer(); 30c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 31c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothApiSocket::BluetoothApiSocket(const std::string& owner_extension_id) 335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu : ApiResource(owner_extension_id), 345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu persistent_(false), 355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu buffer_size_(0), 365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu paused_(false), 375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu connected_(false) { 385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); 395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 41c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochBluetoothApiSocket::BluetoothApiSocket( 42c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const std::string& owner_extension_id, 43c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch scoped_refptr<device::BluetoothSocket> socket, 44c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const std::string& device_address, 45c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const device::BluetoothUUID& uuid) 46c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch : ApiResource(owner_extension_id), 47c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch socket_(socket), 48c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch device_address_(device_address), 49c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch uuid_(uuid), 50c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch persistent_(false), 51c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch buffer_size_(0), 525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu paused_(true), 535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu connected_(true) { 54c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); 55c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 56c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 57c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochBluetoothApiSocket::~BluetoothApiSocket() { 58c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); 595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (socket_.get()) 605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu socket_->Close(); 61c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 62c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 63010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void BluetoothApiSocket::AdoptConnectedSocket( 64010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) scoped_refptr<device::BluetoothSocket> socket, 65010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const std::string& device_address, 66010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const device::BluetoothUUID& uuid) { 67010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); 68010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 69010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (socket_.get()) 70010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) socket_->Close(); 71010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 72010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) socket_ = socket; 73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) device_address_ = device_address; 74010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) uuid_ = uuid; 75010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) connected_ = true; 76010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 77010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothApiSocket::AdoptListeningSocket( 79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_refptr<device::BluetoothSocket> socket, 80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const device::BluetoothUUID& uuid) { 81c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); 825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (socket_.get()) 84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) socket_->Close(); 85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) socket_ = socket; 87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) device_address_ = ""; 88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) uuid_ = uuid; 89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) connected_ = false; 90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothApiSocket::Disconnect(const base::Closure& callback) { 93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); 94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!socket_.get()) { 96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) callback.Run(); 975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) connected_ = false; 101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) socket_->Disconnect(callback); 102c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 103c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 104c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool BluetoothApiSocket::IsPersistent() const { 105c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); 106c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return persistent_; 107c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 108c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 109c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid BluetoothApiSocket::Receive( 110c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int count, 111c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const ReceiveCompletionCallback& success_callback, 1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const ErrorCompletionCallback& error_callback) { 113c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); 1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!socket_.get() || !IsConnected()) { 1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu error_callback.Run(BluetoothApiSocket::kNotConnected, 1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu kSocketNotConnectedError); 1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 121c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch socket_->Receive(count, 122c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch success_callback, 123c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::Bind(&OnSocketReceiveError, error_callback)); 124c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 125c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 126c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// static 127c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid BluetoothApiSocket::OnSocketReceiveError( 1285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const ErrorCompletionCallback& error_callback, 129c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch device::BluetoothSocket::ErrorReason reason, 130c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const std::string& message) { 131c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); 132c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch BluetoothApiSocket::ErrorReason error_reason; 133c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch switch (reason) { 134c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch case device::BluetoothSocket::kIOPending: 135c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch error_reason = BluetoothApiSocket::kIOPending; 136c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch break; 137c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch case device::BluetoothSocket::kDisconnected: 138c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch error_reason = BluetoothApiSocket::kDisconnected; 139c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch break; 140c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch case device::BluetoothSocket::kSystemError: 141c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch error_reason = BluetoothApiSocket::kSystemError; 142c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch break; 143c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 144c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch error_callback.Run(error_reason, message); 145c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 146c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 147c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid BluetoothApiSocket::Send(scoped_refptr<net::IOBuffer> buffer, 148c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int buffer_size, 149c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const SendCompletionCallback& success_callback, 150c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const ErrorCompletionCallback& error_callback) { 151c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); 1525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!socket_.get() || !IsConnected()) { 1545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu error_callback.Run(BluetoothApiSocket::kNotConnected, 1555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu kSocketNotConnectedError); 1565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 1575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu socket_->Send(buffer, 1605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu buffer_size, 1615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu success_callback, 1625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Bind(&OnSocketSendError, error_callback)); 1635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static 1665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BluetoothApiSocket::OnSocketSendError( 1675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const ErrorCompletionCallback& error_callback, 1685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const std::string& message) { 1695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); 1705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu error_callback.Run(BluetoothApiSocket::kSystemError, message); 171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 1725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothApiSocket::Accept( 174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const AcceptCompletionCallback& success_callback, 175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const ErrorCompletionCallback& error_callback) { 176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); 177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!socket_.get() || IsConnected()) { 179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error_callback.Run(BluetoothApiSocket::kNotListening, 180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) kSocketNotListeningError); 181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) socket_->Accept(success_callback, 185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&OnSocketAcceptError, error_callback)); 186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static 189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothApiSocket::OnSocketAcceptError( 190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const ErrorCompletionCallback& error_callback, 191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& message) { 192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(kThreadId)); 193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error_callback.Run(BluetoothApiSocket::kSystemError, message); 194c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 195c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 196c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} // namespace extensions 197