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