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 "device/bluetooth/bluetooth_socket_net.h"
6
7#include <queue>
8#include <string>
9
10#include "base/location.h"
11#include "base/logging.h"
12#include "base/memory/linked_ptr.h"
13#include "base/memory/ref_counted.h"
14#include "base/memory/scoped_ptr.h"
15#include "base/sequenced_task_runner.h"
16#include "base/threading/thread_restrictions.h"
17#include "device/bluetooth/bluetooth_socket.h"
18#include "device/bluetooth/bluetooth_socket_thread.h"
19#include "net/base/io_buffer.h"
20#include "net/base/net_errors.h"
21#include "net/base/net_log.h"
22
23namespace {
24
25const char kSocketNotConnected[] = "Socket is not connected.";
26
27static void DeactivateSocket(
28    const scoped_refptr<device::BluetoothSocketThread>& socket_thread) {
29  socket_thread->OnSocketDeactivate();
30}
31
32}  // namespace
33
34namespace device {
35
36BluetoothSocketNet::WriteRequest::WriteRequest()
37    : buffer_size(0) {}
38
39BluetoothSocketNet::WriteRequest::~WriteRequest() {}
40
41BluetoothSocketNet::BluetoothSocketNet(
42    scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
43    scoped_refptr<BluetoothSocketThread> socket_thread)
44    : ui_task_runner_(ui_task_runner),
45      socket_thread_(socket_thread) {
46  DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
47  socket_thread_->OnSocketActivate();
48}
49
50BluetoothSocketNet::~BluetoothSocketNet() {
51  DCHECK(tcp_socket_.get() == NULL);
52  ui_task_runner_->PostTask(FROM_HERE,
53                            base::Bind(&DeactivateSocket, socket_thread_));
54}
55
56void BluetoothSocketNet::Close() {
57  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
58  socket_thread_->task_runner()->PostTask(
59      FROM_HERE, base::Bind(&BluetoothSocketNet::DoClose, this));
60}
61
62void BluetoothSocketNet::Disconnect(
63    const base::Closure& success_callback) {
64  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
65  socket_thread_->task_runner()->PostTask(
66      FROM_HERE,
67      base::Bind(
68          &BluetoothSocketNet::DoDisconnect,
69          this,
70          base::Bind(&BluetoothSocketNet::PostSuccess,
71                     this,
72                     success_callback)));
73}
74
75void BluetoothSocketNet::Receive(
76    int buffer_size,
77    const ReceiveCompletionCallback& success_callback,
78    const ReceiveErrorCompletionCallback& error_callback) {
79  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
80  socket_thread_->task_runner()->PostTask(
81      FROM_HERE,
82      base::Bind(
83          &BluetoothSocketNet::DoReceive,
84          this,
85          buffer_size,
86          base::Bind(&BluetoothSocketNet::PostReceiveCompletion,
87                     this,
88                     success_callback),
89          base::Bind(&BluetoothSocketNet::PostReceiveErrorCompletion,
90                     this,
91                     error_callback)));
92}
93
94void BluetoothSocketNet::Send(
95    scoped_refptr<net::IOBuffer> buffer,
96    int buffer_size,
97    const SendCompletionCallback& success_callback,
98    const ErrorCompletionCallback& error_callback) {
99  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
100  socket_thread_->task_runner()->PostTask(
101      FROM_HERE,
102      base::Bind(
103          &BluetoothSocketNet::DoSend,
104          this,
105          buffer,
106          buffer_size,
107          base::Bind(&BluetoothSocketNet::PostSendCompletion,
108                     this,
109                     success_callback),
110          base::Bind(&BluetoothSocketNet::PostErrorCompletion,
111                     this,
112                     error_callback)));
113}
114
115void BluetoothSocketNet::ResetData() {
116}
117
118void BluetoothSocketNet::ResetTCPSocket() {
119  tcp_socket_.reset(new net::TCPSocket(NULL, net::NetLog::Source()));
120}
121
122void BluetoothSocketNet::SetTCPSocket(scoped_ptr<net::TCPSocket> tcp_socket) {
123  tcp_socket_ = tcp_socket.Pass();
124}
125
126void BluetoothSocketNet::PostSuccess(const base::Closure& callback) {
127  ui_task_runner_->PostTask(FROM_HERE, callback);
128}
129
130void BluetoothSocketNet::PostErrorCompletion(
131    const ErrorCompletionCallback& callback,
132    const std::string& error) {
133  ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, error));
134}
135
136void BluetoothSocketNet::DoClose() {
137  DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
138  base::ThreadRestrictions::AssertIOAllowed();
139
140  if (tcp_socket_) {
141    tcp_socket_->Close();
142    tcp_socket_.reset(NULL);
143  }
144
145  // Note: Closing |tcp_socket_| above released all potential pending
146  // Send/Receive operations, so we can no safely release the state associated
147  // to those pending operations.
148  read_buffer_ = NULL;
149  std::queue<linked_ptr<WriteRequest> > empty;
150  std::swap(write_queue_, empty);
151
152  ResetData();
153}
154
155void BluetoothSocketNet::DoDisconnect(const base::Closure& callback) {
156  DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
157  base::ThreadRestrictions::AssertIOAllowed();
158
159  DoClose();
160  callback.Run();
161}
162
163void BluetoothSocketNet::DoReceive(
164    int buffer_size,
165    const ReceiveCompletionCallback& success_callback,
166    const ReceiveErrorCompletionCallback& error_callback) {
167  DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
168  base::ThreadRestrictions::AssertIOAllowed();
169
170  if (!tcp_socket_) {
171    error_callback.Run(BluetoothSocket::kDisconnected, kSocketNotConnected);
172    return;
173  }
174
175  // Only one pending read at a time
176  if (read_buffer_.get()) {
177    error_callback.Run(BluetoothSocket::kIOPending,
178                       net::ErrorToString(net::ERR_IO_PENDING));
179    return;
180  }
181
182  scoped_refptr<net::IOBufferWithSize> buffer(
183      new net::IOBufferWithSize(buffer_size));
184  int read_result =
185      tcp_socket_->Read(buffer.get(),
186                        buffer->size(),
187                        base::Bind(&BluetoothSocketNet::OnSocketReadComplete,
188                                   this,
189                                   success_callback,
190                                   error_callback));
191
192  read_buffer_ = buffer;
193  if (read_result != net::ERR_IO_PENDING)
194    OnSocketReadComplete(success_callback, error_callback, read_result);
195}
196
197void BluetoothSocketNet::OnSocketReadComplete(
198    const ReceiveCompletionCallback& success_callback,
199    const ReceiveErrorCompletionCallback& error_callback,
200    int read_result) {
201  DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
202  base::ThreadRestrictions::AssertIOAllowed();
203
204  scoped_refptr<net::IOBufferWithSize> buffer;
205  buffer.swap(read_buffer_);
206  if (read_result > 0) {
207    success_callback.Run(read_result, buffer);
208  } else if (read_result == net::OK ||
209             read_result == net::ERR_CONNECTION_CLOSED ||
210             read_result == net::ERR_CONNECTION_RESET) {
211    error_callback.Run(BluetoothSocket::kDisconnected,
212                       net::ErrorToString(read_result));
213  } else {
214    error_callback.Run(BluetoothSocket::kSystemError,
215                       net::ErrorToString(read_result));
216  }
217}
218
219void BluetoothSocketNet::DoSend(
220    scoped_refptr<net::IOBuffer> buffer,
221    int buffer_size,
222    const SendCompletionCallback& success_callback,
223    const ErrorCompletionCallback& error_callback) {
224  DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
225  base::ThreadRestrictions::AssertIOAllowed();
226
227  if (!tcp_socket_) {
228    error_callback.Run(kSocketNotConnected);
229    return;
230  }
231
232  linked_ptr<WriteRequest> request(new WriteRequest());
233  request->buffer = buffer;
234  request->buffer_size = buffer_size;
235  request->success_callback = success_callback;
236  request->error_callback = error_callback;
237
238  write_queue_.push(request);
239  if (write_queue_.size() == 1) {
240    SendFrontWriteRequest();
241  }
242}
243
244void BluetoothSocketNet::SendFrontWriteRequest() {
245  DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
246  base::ThreadRestrictions::AssertIOAllowed();
247
248  if (!tcp_socket_)
249    return;
250
251  if (write_queue_.size() == 0)
252    return;
253
254  linked_ptr<WriteRequest> request = write_queue_.front();
255  net::CompletionCallback callback =
256      base::Bind(&BluetoothSocketNet::OnSocketWriteComplete,
257                 this,
258                 request->success_callback,
259                 request->error_callback);
260  int send_result =
261      tcp_socket_->Write(request->buffer.get(), request->buffer_size, callback);
262  if (send_result != net::ERR_IO_PENDING) {
263    callback.Run(send_result);
264  }
265}
266
267void BluetoothSocketNet::OnSocketWriteComplete(
268    const SendCompletionCallback& success_callback,
269    const ErrorCompletionCallback& error_callback,
270    int send_result) {
271  DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
272  base::ThreadRestrictions::AssertIOAllowed();
273
274  write_queue_.pop();
275
276  if (send_result >= net::OK) {
277    success_callback.Run(send_result);
278  } else {
279    error_callback.Run(net::ErrorToString(send_result));
280  }
281
282  // Don't call directly to avoid potentail large recursion.
283  socket_thread_->task_runner()->PostNonNestableTask(
284      FROM_HERE,
285      base::Bind(&BluetoothSocketNet::SendFrontWriteRequest, this));
286}
287
288void BluetoothSocketNet::PostReceiveCompletion(
289    const ReceiveCompletionCallback& callback,
290    int io_buffer_size,
291    scoped_refptr<net::IOBuffer> io_buffer) {
292  ui_task_runner_->PostTask(FROM_HERE,
293                            base::Bind(callback, io_buffer_size, io_buffer));
294}
295
296void BluetoothSocketNet::PostReceiveErrorCompletion(
297    const ReceiveErrorCompletionCallback& callback,
298    ErrorReason reason,
299    const std::string& error_message) {
300  ui_task_runner_->PostTask(FROM_HERE,
301                            base::Bind(callback, reason, error_message));
302}
303
304void BluetoothSocketNet::PostSendCompletion(
305    const SendCompletionCallback& callback,
306    int bytes_written) {
307  ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, bytes_written));
308}
309
310}  // namespace device
311