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