Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "device/bluetooth/bluetooth_socket_win.h" | 5 #include "device/bluetooth/bluetooth_socket_win.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/memory/ref_counted.h" | 10 #include "base/memory/ref_counted.h" |
| 11 #include "base/sequenced_task_runner.h" | |
| 11 #include "base/strings/sys_string_conversions.h" | 12 #include "base/strings/sys_string_conversions.h" |
| 13 #include "base/threading/thread_restrictions.h" | |
| 12 #include "device/bluetooth/bluetooth_init_win.h" | 14 #include "device/bluetooth/bluetooth_init_win.h" |
| 13 #include "device/bluetooth/bluetooth_service_record_win.h" | 15 #include "device/bluetooth/bluetooth_service_record_win.h" |
| 16 #include "device/bluetooth/bluetooth_socket_thread_win.h" | |
| 14 #include "net/base/io_buffer.h" | 17 #include "net/base/io_buffer.h" |
| 18 #include "net/base/ip_endpoint.h" | |
| 19 #include "net/base/net_errors.h" | |
| 15 #include "net/base/winsock_init.h" | 20 #include "net/base/winsock_init.h" |
| 21 #include "net/socket/tcp_socket_win.h" | |
|
jar (doing other things)
2014/04/04 21:35:49
nit: better might be to include net/socket/tcp_soc
rpaquay
2014/04/04 22:27:58
Done.
| |
| 16 | 22 |
| 17 namespace { | 23 namespace { |
| 18 | 24 |
| 25 const char kL2CAPNotSupported[] = "Bluetooth L2CAP protocal is not supported"; | |
| 26 const char kSocketAlreadyConnected[] = "Socket is already connected."; | |
| 27 const char kSocketNotConnected[] = "Socket is not connected."; | |
| 28 | |
| 29 using device::BluetoothSocketWin; | |
| 30 | |
| 19 std::string FormatErrorMessage(DWORD error_code) { | 31 std::string FormatErrorMessage(DWORD error_code) { |
| 20 TCHAR error_msg[1024]; | 32 TCHAR error_msg[1024]; |
| 21 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, | 33 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, |
| 22 0, | 34 0, |
| 23 error_code, | 35 error_code, |
| 24 0, | 36 0, |
| 25 error_msg, | 37 error_msg, |
| 26 1024, | 38 1024, |
| 27 NULL); | 39 NULL); |
| 28 return base::SysWideToUTF8(error_msg); | 40 return base::SysWideToUTF8(error_msg); |
| 29 } | 41 } |
| 30 | 42 |
| 43 static void DeactivateSocket( | |
| 44 const scoped_refptr<device::BluetoothSocketThreadWin>& socket_thread) { | |
| 45 socket_thread->OnSocketDeactivate(); | |
| 46 } | |
| 47 | |
| 31 } // namespace | 48 } // namespace |
| 32 | 49 |
| 33 namespace device { | 50 namespace device { |
| 34 | 51 |
| 35 BluetoothSocketWin::BluetoothSocketWin(SOCKET fd) : fd_(fd) { | 52 // static |
| 53 scoped_refptr<BluetoothSocketWin> BluetoothSocketWin::CreateBluetoothSocket( | |
| 54 const BluetoothServiceRecord& service_record, | |
| 55 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, | |
| 56 scoped_refptr<BluetoothSocketThreadWin> socket_thread, | |
| 57 net::NetLog* net_log, | |
| 58 const net::NetLog::Source& source) { | |
| 59 DCHECK(ui_task_runner->RunsTasksOnCurrentThread()); | |
| 60 const BluetoothServiceRecordWin* service_record_win = | |
| 61 static_cast<const BluetoothServiceRecordWin*>(&service_record); | |
| 62 | |
| 63 scoped_refptr<BluetoothSocketWin> result( | |
| 64 new BluetoothSocketWin(ui_task_runner, socket_thread, net_log, source)); | |
| 65 result->device_address_ = service_record_win->address(); | |
| 66 if (service_record.SupportsRfcomm()) { | |
| 67 result->supports_rfcomm_ = true; | |
| 68 result->rfcomm_channel_ = service_record_win->rfcomm_channel(); | |
| 69 result->bth_addr_ = service_record_win->bth_addr(); | |
| 70 } | |
| 71 | |
| 72 return result; | |
| 73 } | |
| 74 | |
| 75 BluetoothSocketWin::BluetoothSocketWin( | |
| 76 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, | |
| 77 scoped_refptr<BluetoothSocketThreadWin> socket_thread, | |
| 78 net::NetLog* net_log, | |
| 79 const net::NetLog::Source& source) | |
| 80 : ui_task_runner_(ui_task_runner), | |
| 81 socket_thread_(socket_thread), | |
| 82 net_log_(net_log), | |
| 83 source_(source), | |
| 84 supports_rfcomm_(false), | |
| 85 rfcomm_channel_(-1), | |
| 86 bth_addr_(BTH_ADDR_NULL) { | |
| 87 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | |
| 88 socket_thread->OnSocketActivate(); | |
| 36 } | 89 } |
| 37 | 90 |
| 38 BluetoothSocketWin::~BluetoothSocketWin() { | 91 BluetoothSocketWin::~BluetoothSocketWin() { |
| 39 closesocket(fd_); | 92 ui_task_runner_->PostTask(FROM_HERE, |
| 40 } | 93 base::Bind(&DeactivateSocket, socket_thread_)); |
| 41 | 94 } |
| 42 // static | 95 |
| 43 scoped_refptr<BluetoothSocket> BluetoothSocketWin::CreateBluetoothSocket( | 96 void BluetoothSocketWin::Release() { |
| 44 const BluetoothServiceRecord& service_record) { | 97 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 45 BluetoothSocketWin* bluetooth_socket = NULL; | 98 socket_thread_->task_runner()->PostTask( |
| 46 if (service_record.SupportsRfcomm()) { | 99 FROM_HERE, base::Bind(&BluetoothSocketWin::DoRelease, this)); |
| 47 net::EnsureWinsockInit(); | 100 } |
| 48 SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); | 101 |
| 49 SOCKADDR_BTH sa; | 102 void BluetoothSocketWin::Connect( |
| 50 ZeroMemory(&sa, sizeof(sa)); | 103 const base::Closure& success_callback, |
| 51 sa.addressFamily = AF_BTH; | 104 const ErrorCompletionCallback& error_callback) { |
| 52 sa.port = service_record.rfcomm_channel(); | 105 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 53 const BluetoothServiceRecordWin* service_record_win = | 106 socket_thread_->task_runner()->PostTask( |
| 54 static_cast<const BluetoothServiceRecordWin*>(&service_record); | 107 FROM_HERE, |
| 55 sa.btAddr = service_record_win->bth_addr(); | 108 base::Bind( |
| 56 | 109 &BluetoothSocketWin::DoConnect, |
| 57 int status = connect(socket_fd, | 110 this, |
| 58 reinterpret_cast<SOCKADDR *>(&sa), | 111 base::Bind(&BluetoothSocketWin::PostSuccess, this, success_callback), |
| 59 sizeof(sa)); | 112 base::Bind( |
| 60 DWORD error_code = WSAGetLastError(); | 113 &BluetoothSocketWin::PostErrorCompletion, this, error_callback))); |
| 61 if (status == 0 || error_code == WSAEINPROGRESS) { | 114 } |
| 62 bluetooth_socket = | 115 |
| 63 new BluetoothSocketWin(socket_fd); | 116 void BluetoothSocketWin::Disconnect(const base::Closure& success_callback) { |
| 64 } else { | 117 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 65 LOG(ERROR) << "Failed to connect bluetooth socket " | 118 socket_thread_->task_runner()->PostTask( |
| 66 << "(" << service_record.address() << "): " | 119 FROM_HERE, |
| 67 << "(" << error_code << ")" << FormatErrorMessage(error_code); | 120 base::Bind( |
| 68 closesocket(socket_fd); | 121 &BluetoothSocketWin::DoDisconnect, |
| 69 } | 122 this, |
| 70 } | 123 base::Bind( |
| 71 // TODO(youngki) add support for L2CAP sockets as well. | 124 &BluetoothSocketWin::PostSuccess, this, success_callback))); |
| 72 | 125 } |
| 73 return scoped_refptr<BluetoothSocketWin>(bluetooth_socket); | 126 |
| 74 } | 127 void BluetoothSocketWin::Receive( |
| 75 | 128 int count, |
| 76 bool BluetoothSocketWin::Receive(net::GrowableIOBuffer* buffer) { | 129 const ReceiveCompletionCallback& success_callback, |
| 77 buffer->SetCapacity(1024); | 130 const ReceiveErrorCompletionCallback& error_callback) { |
| 78 int bytes_read; | 131 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 79 do { | 132 socket_thread_->task_runner()->PostTask( |
| 80 if (buffer->RemainingCapacity() == 0) | 133 FROM_HERE, |
| 81 buffer->SetCapacity(buffer->capacity() * 2); | 134 base::Bind(&BluetoothSocketWin::DoReceive, |
| 82 bytes_read = recv(fd_, buffer->data(), buffer->RemainingCapacity(), 0); | 135 this, |
| 83 if (bytes_read > 0) | 136 count, |
| 84 buffer->set_offset(buffer->offset() + bytes_read); | 137 base::Bind(&BluetoothSocketWin::PostReceiveCompletion, |
| 85 } while (bytes_read > 0); | 138 this, |
| 86 | 139 success_callback), |
| 140 base::Bind(&BluetoothSocketWin::PostReceiveErrorCompletion, | |
| 141 this, | |
| 142 error_callback))); | |
| 143 } | |
| 144 | |
| 145 void BluetoothSocketWin::Send(scoped_refptr<net::IOBuffer> buffer, | |
| 146 int buffer_size, | |
| 147 const SendCompletionCallback& success_callback, | |
| 148 const ErrorCompletionCallback& error_callback) { | |
| 149 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | |
| 150 socket_thread_->task_runner()->PostTask( | |
| 151 FROM_HERE, | |
| 152 base::Bind( | |
| 153 &BluetoothSocketWin::DoSend, | |
| 154 this, | |
| 155 buffer, | |
| 156 buffer_size, | |
| 157 base::Bind( | |
| 158 &BluetoothSocketWin::PostSendCompletion, this, success_callback), | |
| 159 base::Bind( | |
| 160 &BluetoothSocketWin::PostErrorCompletion, this, error_callback))); | |
| 161 } | |
| 162 | |
| 163 void BluetoothSocketWin::DoRelease() { | |
| 164 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); | |
| 165 base::ThreadRestrictions::AssertIOAllowed(); | |
| 166 | |
| 167 if (socket_win_) { | |
| 168 socket_win_->Close(); | |
| 169 socket_win_.reset(NULL); | |
| 170 } | |
| 171 | |
| 172 // Note: Closing |socket_win_| above released all potential pending | |
| 173 // Send/Receive operations, so we can no safely release the state associated | |
| 174 // to those pending operations. | |
| 175 read_buffer_ = NULL; | |
| 176 std::queue<linked_ptr<WriteRequest> > empty; | |
| 177 write_queue_.swap(empty); | |
| 178 } | |
| 179 | |
| 180 void BluetoothSocketWin::DoConnect( | |
| 181 const base::Closure& success_callback, | |
| 182 const ErrorCompletionCallback& error_callback) { | |
| 183 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); | |
| 184 base::ThreadRestrictions::AssertIOAllowed(); | |
| 185 | |
| 186 if (socket_win_) { | |
| 187 error_callback.Run(kSocketAlreadyConnected); | |
| 188 return; | |
| 189 } | |
| 190 | |
| 191 if (!supports_rfcomm_) { | |
| 192 // TODO(youngki) add support for L2CAP sockets as well. | |
| 193 error_callback.Run(kL2CAPNotSupported); | |
| 194 return; | |
| 195 } | |
| 196 | |
| 197 socket_win_.reset(new net::TCPSocketWin(net_log_, source_)); | |
|
jar (doing other things)
2014/04/04 21:35:49
nit: Better is probably to use generic name TCPSoc
rpaquay
2014/04/04 22:27:58
Done.
| |
| 198 net::EnsureWinsockInit(); | |
| 199 SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); | |
| 200 SOCKADDR_BTH sa; | |
| 201 ZeroMemory(&sa, sizeof(sa)); | |
| 202 sa.addressFamily = AF_BTH; | |
| 203 sa.port = rfcomm_channel_; | |
| 204 sa.btAddr = bth_addr_; | |
| 205 | |
| 206 // TODO(rpaquay): Condider making this call non-blocking. | |
| 207 int status = connect(socket_fd, reinterpret_cast<SOCKADDR*>(&sa), sizeof(sa)); | |
| 87 DWORD error_code = WSAGetLastError(); | 208 DWORD error_code = WSAGetLastError(); |
| 88 if (bytes_read < 0 && error_code != WSAEWOULDBLOCK) { | 209 if (!(status == 0 || error_code == WSAEINPROGRESS)) { |
| 89 error_message_ = FormatErrorMessage(error_code); | 210 LOG(ERROR) << "Failed to connect bluetooth socket " |
| 90 return false; | 211 << "(" << device_address_ << "): " |
| 91 } | 212 << "(" << error_code << ")" << FormatErrorMessage(error_code); |
| 92 return true; | 213 error_callback.Run("Error connecting to socket: " + |
| 93 } | 214 FormatErrorMessage(error_code)); |
| 94 | 215 closesocket(socket_fd); |
| 95 bool BluetoothSocketWin::Send(net::DrainableIOBuffer* buffer) { | 216 return; |
| 96 int bytes_written; | 217 } |
| 97 do { | 218 |
| 98 bytes_written = send(fd_, buffer->data(), buffer->BytesRemaining(), 0); | 219 // Note: We don't have a meaningful |IPEndPoint|, but that is ok since the |
| 99 if (bytes_written > 0) | 220 // TCPSocketWin implementation does not actually require one. |
| 100 buffer->DidConsume(bytes_written); | 221 int net_result = |
| 101 } while (buffer->BytesRemaining() > 0 && bytes_written > 0); | 222 socket_win_->AdoptConnectedSocket(socket_fd, net::IPEndPoint()); |
| 102 | 223 if (net_result != net::OK) { |
| 103 DWORD error_code = WSAGetLastError(); | 224 error_callback.Run("Error connecting to socket: " + |
| 104 if (bytes_written < 0 && error_code != WSAEWOULDBLOCK) { | 225 std::string(net::ErrorToString(net_result))); |
| 105 error_message_ = FormatErrorMessage(error_code); | 226 closesocket(socket_fd); |
| 106 return false; | 227 return; |
| 107 } | 228 } |
| 108 return true; | 229 |
| 109 } | 230 success_callback.Run(); |
| 110 | 231 } |
| 111 std::string BluetoothSocketWin::GetLastErrorMessage() const { | 232 |
| 112 return error_message_; | 233 void BluetoothSocketWin::DoDisconnect(const base::Closure& success_callback) { |
| 234 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); | |
| 235 base::ThreadRestrictions::AssertIOAllowed(); | |
| 236 | |
| 237 DoRelease(); | |
| 238 success_callback.Run(); | |
| 239 } | |
| 240 | |
| 241 void BluetoothSocketWin::DoReceive( | |
| 242 int count, | |
| 243 const ReceiveCompletionCallback& success_callback, | |
| 244 const ReceiveErrorCompletionCallback& error_callback) { | |
| 245 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); | |
| 246 base::ThreadRestrictions::AssertIOAllowed(); | |
| 247 | |
| 248 if (!socket_win_) { | |
| 249 error_callback.Run(BluetoothSocketWin::kDisconnected, kSocketNotConnected); | |
| 250 return; | |
| 251 } | |
| 252 | |
| 253 // Only one pending read at a time | |
| 254 if (read_buffer_.get()) { | |
| 255 error_callback.Run(BluetoothSocketWin::kIOPending, | |
| 256 net::ErrorToString(net::ERR_IO_PENDING)); | |
| 257 return; | |
| 258 } | |
| 259 | |
| 260 scoped_refptr<net::IOBufferWithSize> buffer(new net::IOBufferWithSize(count)); | |
| 261 int read_result = | |
| 262 socket_win_->Read(buffer.get(), | |
| 263 buffer->size(), | |
| 264 base::Bind(&BluetoothSocketWin::OnSocketReadComplete, | |
| 265 this, | |
| 266 success_callback, | |
| 267 error_callback)); | |
| 268 | |
| 269 if (read_result > 0) { | |
| 270 success_callback.Run(read_result, buffer); | |
| 271 } else if (read_result == net::OK || | |
| 272 read_result == net::ERR_CONNECTION_CLOSED) { | |
| 273 error_callback.Run(BluetoothSocketWin::kDisconnected, | |
| 274 net::ErrorToString(net::ERR_CONNECTION_CLOSED)); | |
| 275 } else if (read_result == net::ERR_IO_PENDING) { | |
| 276 read_buffer_ = buffer; | |
| 277 } else { | |
| 278 error_callback.Run(BluetoothSocketWin::kSystemError, | |
| 279 net::ErrorToString(read_result)); | |
| 280 } | |
| 281 } | |
| 282 | |
| 283 void BluetoothSocketWin::OnSocketReadComplete( | |
| 284 const ReceiveCompletionCallback& success_callback, | |
| 285 const ReceiveErrorCompletionCallback& error_callback, | |
| 286 int read_result) { | |
| 287 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); | |
| 288 base::ThreadRestrictions::AssertIOAllowed(); | |
| 289 | |
| 290 scoped_refptr<net::IOBufferWithSize> buffer; | |
| 291 buffer.swap(read_buffer_); | |
| 292 if (read_result > 0) { | |
| 293 success_callback.Run(read_result, buffer); | |
| 294 } else if (read_result == net::OK || | |
| 295 read_result == net::ERR_CONNECTION_CLOSED) { | |
| 296 error_callback.Run(BluetoothSocketWin::kDisconnected, | |
| 297 net::ErrorToString(net::ERR_CONNECTION_CLOSED)); | |
| 298 } else { | |
| 299 error_callback.Run(BluetoothSocketWin::kSystemError, | |
| 300 net::ErrorToString(read_result)); | |
| 301 } | |
| 302 } | |
| 303 | |
| 304 void BluetoothSocketWin::DoSend(scoped_refptr<net::IOBuffer> buffer, | |
| 305 int buffer_size, | |
| 306 const SendCompletionCallback& success_callback, | |
| 307 const ErrorCompletionCallback& error_callback) { | |
| 308 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); | |
| 309 base::ThreadRestrictions::AssertIOAllowed(); | |
| 310 | |
| 311 if (!socket_win_) { | |
| 312 error_callback.Run(kSocketNotConnected); | |
| 313 return; | |
| 314 } | |
| 315 | |
| 316 linked_ptr<WriteRequest> request(new WriteRequest()); | |
| 317 request->buffer = buffer; | |
| 318 request->buffer_size = buffer_size; | |
| 319 request->success_callback = success_callback; | |
| 320 request->error_callback = error_callback; | |
| 321 | |
| 322 write_queue_.push(request); | |
| 323 if (write_queue_.size() == 1) { | |
| 324 SendFrontWriteRequest(); | |
| 325 } | |
| 326 } | |
| 327 | |
| 328 void BluetoothSocketWin::SendFrontWriteRequest() { | |
| 329 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); | |
| 330 base::ThreadRestrictions::AssertIOAllowed(); | |
| 331 | |
| 332 if (!socket_win_) | |
| 333 return; | |
| 334 | |
| 335 if (write_queue_.size() == 0) | |
| 336 return; | |
| 337 | |
| 338 linked_ptr<WriteRequest> request = write_queue_.front(); | |
| 339 net::CompletionCallback callback = | |
| 340 base::Bind(&BluetoothSocketWin::OnSocketWriteComplete, | |
| 341 this, | |
| 342 request->success_callback, | |
| 343 request->error_callback); | |
| 344 int send_result = | |
| 345 socket_win_->Write(request->buffer, request->buffer_size, callback); | |
| 346 if (send_result != net::ERR_IO_PENDING) { | |
| 347 callback.Run(send_result); | |
| 348 } | |
| 349 } | |
| 350 | |
| 351 void BluetoothSocketWin::OnSocketWriteComplete( | |
| 352 const SendCompletionCallback& success_callback, | |
| 353 const ErrorCompletionCallback& error_callback, | |
| 354 int send_result) { | |
| 355 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); | |
| 356 base::ThreadRestrictions::AssertIOAllowed(); | |
| 357 | |
| 358 write_queue_.pop(); | |
| 359 | |
| 360 if (send_result >= net::OK) { | |
| 361 success_callback.Run(send_result); | |
| 362 } else { | |
| 363 error_callback.Run(net::ErrorToString(send_result)); | |
| 364 } | |
| 365 | |
| 366 // Don't call directly to avoid potentail large recursion. | |
| 367 socket_thread_->task_runner()->PostNonNestableTask( | |
| 368 FROM_HERE, base::Bind(&BluetoothSocketWin::SendFrontWriteRequest, this)); | |
| 369 } | |
| 370 | |
| 371 void BluetoothSocketWin::PostSuccess(const base::Closure& callback) { | |
| 372 ui_task_runner_->PostTask(FROM_HERE, callback); | |
| 373 } | |
| 374 | |
| 375 void BluetoothSocketWin::PostErrorCompletion( | |
| 376 const ErrorCompletionCallback& callback, | |
| 377 const std::string& error) { | |
| 378 ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, error)); | |
| 379 } | |
| 380 | |
| 381 void BluetoothSocketWin::PostReceiveCompletion( | |
| 382 const ReceiveCompletionCallback& callback, | |
| 383 int io_buffer_size, | |
| 384 scoped_refptr<net::IOBuffer> io_buffer) { | |
| 385 ui_task_runner_->PostTask(FROM_HERE, | |
| 386 base::Bind(callback, io_buffer_size, io_buffer)); | |
| 387 } | |
| 388 | |
| 389 void BluetoothSocketWin::PostReceiveErrorCompletion( | |
| 390 const ReceiveErrorCompletionCallback& callback, | |
| 391 ErrorReason reason, | |
| 392 const std::string& error_message) { | |
| 393 ui_task_runner_->PostTask(FROM_HERE, | |
| 394 base::Bind(callback, reason, error_message)); | |
| 395 } | |
| 396 | |
| 397 void BluetoothSocketWin::PostSendCompletion( | |
| 398 const SendCompletionCallback& callback, | |
| 399 int bytes_written) { | |
| 400 ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, bytes_written)); | |
| 113 } | 401 } |
| 114 | 402 |
| 115 } // namespace device | 403 } // namespace device |
| OLD | NEW |