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_api_socket.h"
6
7#include "device/bluetooth/bluetooth_socket.h"
8#include "net/base/io_buffer.h"
9
10namespace {
11
12const char kSocketNotConnectedError[] = "Socket not connected";
13const char kSocketNotListeningError[] = "Socket not listening";
14
15}  // namespace
16
17namespace extensions {
18
19// static
20static base::LazyInstance<
21    BrowserContextKeyedAPIFactory<ApiResourceManager<BluetoothApiSocket> > >
22    g_server_factory = LAZY_INSTANCE_INITIALIZER;
23
24// static
25template <>
26BrowserContextKeyedAPIFactory<ApiResourceManager<BluetoothApiSocket> >*
27ApiResourceManager<BluetoothApiSocket>::GetFactoryInstance() {
28  return g_server_factory.Pointer();
29}
30
31BluetoothApiSocket::BluetoothApiSocket(const std::string& owner_extension_id)
32    : ApiResource(owner_extension_id),
33      persistent_(false),
34      buffer_size_(0),
35      paused_(false),
36      connected_(false) {
37  DCHECK(content::BrowserThread::CurrentlyOn(kThreadId));
38}
39
40BluetoothApiSocket::BluetoothApiSocket(
41    const std::string& owner_extension_id,
42    scoped_refptr<device::BluetoothSocket> socket,
43    const std::string& device_address,
44    const device::BluetoothUUID& uuid)
45    : ApiResource(owner_extension_id),
46      socket_(socket),
47      device_address_(device_address),
48      uuid_(uuid),
49      persistent_(false),
50      buffer_size_(0),
51      paused_(true),
52      connected_(true) {
53  DCHECK(content::BrowserThread::CurrentlyOn(kThreadId));
54}
55
56BluetoothApiSocket::~BluetoothApiSocket() {
57  DCHECK(content::BrowserThread::CurrentlyOn(kThreadId));
58  if (socket_.get())
59    socket_->Close();
60}
61
62void BluetoothApiSocket::AdoptConnectedSocket(
63    scoped_refptr<device::BluetoothSocket> socket,
64    const std::string& device_address,
65    const device::BluetoothUUID& uuid) {
66  DCHECK(content::BrowserThread::CurrentlyOn(kThreadId));
67
68  if (socket_.get())
69    socket_->Close();
70
71  socket_ = socket;
72  device_address_ = device_address;
73  uuid_ = uuid;
74  connected_ = true;
75}
76
77void BluetoothApiSocket::AdoptListeningSocket(
78    scoped_refptr<device::BluetoothSocket> socket,
79    const device::BluetoothUUID& uuid) {
80  DCHECK(content::BrowserThread::CurrentlyOn(kThreadId));
81
82  if (socket_.get())
83    socket_->Close();
84
85  socket_ = socket;
86  device_address_ = "";
87  uuid_ = uuid;
88  connected_ = false;
89}
90
91void BluetoothApiSocket::Disconnect(const base::Closure& callback) {
92  DCHECK(content::BrowserThread::CurrentlyOn(kThreadId));
93
94  if (!socket_.get()) {
95    callback.Run();
96    return;
97  }
98
99  connected_ = false;
100  socket_->Disconnect(callback);
101}
102
103bool BluetoothApiSocket::IsPersistent() const {
104  DCHECK(content::BrowserThread::CurrentlyOn(kThreadId));
105  return persistent_;
106}
107
108void BluetoothApiSocket::Receive(
109    int count,
110    const ReceiveCompletionCallback& success_callback,
111    const ErrorCompletionCallback& error_callback) {
112  DCHECK(content::BrowserThread::CurrentlyOn(kThreadId));
113
114  if (!socket_.get() || !IsConnected()) {
115    error_callback.Run(BluetoothApiSocket::kNotConnected,
116                       kSocketNotConnectedError);
117    return;
118  }
119
120  socket_->Receive(count,
121                   success_callback,
122                   base::Bind(&OnSocketReceiveError, error_callback));
123}
124
125// static
126void BluetoothApiSocket::OnSocketReceiveError(
127    const ErrorCompletionCallback& error_callback,
128    device::BluetoothSocket::ErrorReason reason,
129    const std::string& message) {
130  DCHECK(content::BrowserThread::CurrentlyOn(kThreadId));
131  BluetoothApiSocket::ErrorReason error_reason;
132  switch (reason) {
133    case device::BluetoothSocket::kIOPending:
134      error_reason = BluetoothApiSocket::kIOPending;
135      break;
136    case device::BluetoothSocket::kDisconnected:
137      error_reason = BluetoothApiSocket::kDisconnected;
138      break;
139    case device::BluetoothSocket::kSystemError:
140      error_reason = BluetoothApiSocket::kSystemError;
141      break;
142    default:
143      NOTREACHED();
144  }
145  error_callback.Run(error_reason, message);
146}
147
148void BluetoothApiSocket::Send(scoped_refptr<net::IOBuffer> buffer,
149                              int buffer_size,
150                              const SendCompletionCallback& success_callback,
151                              const ErrorCompletionCallback& error_callback) {
152  DCHECK(content::BrowserThread::CurrentlyOn(kThreadId));
153
154  if (!socket_.get() || !IsConnected()) {
155    error_callback.Run(BluetoothApiSocket::kNotConnected,
156                       kSocketNotConnectedError);
157    return;
158  }
159
160  socket_->Send(buffer,
161                buffer_size,
162                success_callback,
163                base::Bind(&OnSocketSendError, error_callback));
164}
165
166// static
167void BluetoothApiSocket::OnSocketSendError(
168    const ErrorCompletionCallback& error_callback,
169    const std::string& message) {
170  DCHECK(content::BrowserThread::CurrentlyOn(kThreadId));
171  error_callback.Run(BluetoothApiSocket::kSystemError, message);
172}
173
174void BluetoothApiSocket::Accept(
175    const AcceptCompletionCallback& success_callback,
176    const ErrorCompletionCallback& error_callback) {
177  DCHECK(content::BrowserThread::CurrentlyOn(kThreadId));
178
179  if (!socket_.get() || IsConnected()) {
180    error_callback.Run(BluetoothApiSocket::kNotListening,
181                       kSocketNotListeningError);
182    return;
183  }
184
185  socket_->Accept(success_callback,
186                  base::Bind(&OnSocketAcceptError, error_callback));
187}
188
189// static
190void BluetoothApiSocket::OnSocketAcceptError(
191    const ErrorCompletionCallback& error_callback,
192    const std::string& message) {
193  DCHECK(content::BrowserThread::CurrentlyOn(kThreadId));
194  error_callback.Run(BluetoothApiSocket::kSystemError, message);
195}
196
197}  // namespace extensions
198