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