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