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/strings/sys_string_conversions.h" | 11 #include "base/strings/sys_string_conversions.h" |
| 12 #include "base/threading/thread_restrictions.h" |
12 #include "device/bluetooth/bluetooth_init_win.h" | 13 #include "device/bluetooth/bluetooth_init_win.h" |
13 #include "device/bluetooth/bluetooth_service_record_win.h" | 14 #include "device/bluetooth/bluetooth_service_record_win.h" |
14 #include "net/base/io_buffer.h" | 15 #include "net/base/io_buffer.h" |
| 16 #include "net/base/ip_endpoint.h" |
| 17 #include "net/base/net_errors.h" |
15 #include "net/base/winsock_init.h" | 18 #include "net/base/winsock_init.h" |
| 19 #include "net/socket/tcp_socket_win.h" |
16 | 20 |
17 namespace { | 21 namespace { |
18 | 22 |
| 23 const char kL2CAPNotSupported[] = "Bluetooth L2CAP protocal is not supported"; |
| 24 const char kSocketAlreadyConnected[] = "Socket is already connected."; |
| 25 const char kSocketNotConnected[] = "Socket is not connected."; |
| 26 |
19 std::string FormatErrorMessage(DWORD error_code) { | 27 std::string FormatErrorMessage(DWORD error_code) { |
20 TCHAR error_msg[1024]; | 28 TCHAR error_msg[1024]; |
21 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, | 29 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, |
22 0, | 30 0, |
23 error_code, | 31 error_code, |
24 0, | 32 0, |
25 error_msg, | 33 error_msg, |
26 1024, | 34 1024, |
27 NULL); | 35 NULL); |
28 return base::SysWideToUTF8(error_msg); | 36 return base::SysWideToUTF8(error_msg); |
29 } | 37 } |
30 | 38 |
31 } // namespace | 39 } // namespace |
32 | 40 |
33 namespace device { | 41 namespace device { |
34 | 42 |
35 BluetoothSocketWin::BluetoothSocketWin(SOCKET fd) : fd_(fd) { | 43 BluetoothSocketWin::BluetoothSocketWin( |
36 } | 44 scoped_refptr<base::SequencedTaskRunner> task_runner, |
| 45 net::NetLog* net_log, |
| 46 const net::NetLog::Source& source) |
| 47 : task_runner_(task_runner), |
| 48 net_log_(net_log), |
| 49 source_(source), |
| 50 supports_rfcomm_(false), |
| 51 rfcomm_channel_(-1), |
| 52 bth_addr_(BTH_ADDR_NULL) {} |
37 | 53 |
38 BluetoothSocketWin::~BluetoothSocketWin() { | 54 BluetoothSocketWin::~BluetoothSocketWin() { |
39 closesocket(fd_); | 55 DCHECK(thread_checker_.CalledOnValidThread()); |
40 } | 56 } |
41 | 57 |
42 // static | 58 // static |
43 scoped_refptr<BluetoothSocket> BluetoothSocketWin::CreateBluetoothSocket( | 59 scoped_refptr<BluetoothSocket> BluetoothSocketWin::CreateBluetoothSocket( |
44 const BluetoothServiceRecord& service_record) { | 60 const BluetoothServiceRecord& service_record, |
45 BluetoothSocketWin* bluetooth_socket = NULL; | 61 scoped_refptr<base::SequencedTaskRunner> task_runner, |
| 62 net::NetLog* net_log, |
| 63 const net::NetLog::Source& source) { |
| 64 const BluetoothServiceRecordWin* service_record_win = |
| 65 static_cast<const BluetoothServiceRecordWin*>(&service_record); |
| 66 |
| 67 scoped_refptr<BluetoothSocketWin> result( |
| 68 new BluetoothSocketWin(task_runner, net_log, source)); |
| 69 result->device_address_ = service_record_win->address(); |
46 if (service_record.SupportsRfcomm()) { | 70 if (service_record.SupportsRfcomm()) { |
47 net::EnsureWinsockInit(); | 71 result->supports_rfcomm_ = true; |
48 SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); | 72 result->rfcomm_channel_ = service_record_win->rfcomm_channel(); |
49 SOCKADDR_BTH sa; | 73 result->bth_addr_ = service_record_win->bth_addr(); |
50 ZeroMemory(&sa, sizeof(sa)); | 74 } |
51 sa.addressFamily = AF_BTH; | 75 |
52 sa.port = service_record.rfcomm_channel(); | 76 // Underlying socket is used on a different thread. |
53 const BluetoothServiceRecordWin* service_record_win = | 77 result->thread_checker_.DetachFromThread(); |
54 static_cast<const BluetoothServiceRecordWin*>(&service_record); | 78 return result; |
55 sa.btAddr = service_record_win->bth_addr(); | 79 } |
56 | 80 |
57 int status = connect(socket_fd, | 81 void BluetoothSocketWin::Connect( |
58 reinterpret_cast<SOCKADDR *>(&sa), | 82 const base::Closure& success_callback, |
59 sizeof(sa)); | 83 const ErrorCompletionCallback& error_callback) { |
60 DWORD error_code = WSAGetLastError(); | 84 DCHECK(thread_checker_.CalledOnValidThread()); |
61 if (status == 0 || error_code == WSAEINPROGRESS) { | 85 base::ThreadRestrictions::AssertIOAllowed(); |
62 bluetooth_socket = | 86 |
63 new BluetoothSocketWin(socket_fd); | 87 if (socket_win_) { |
64 } else { | 88 error_callback.Run(kSocketAlreadyConnected); |
65 LOG(ERROR) << "Failed to connect bluetooth socket " | 89 return; |
66 << "(" << service_record.address() << "): " | 90 } |
67 << "(" << error_code << ")" << FormatErrorMessage(error_code); | 91 |
68 closesocket(socket_fd); | 92 if (!supports_rfcomm_) { |
69 } | 93 // TODO(youngki) add support for L2CAP sockets as well. |
70 } | 94 error_callback.Run(kL2CAPNotSupported); |
71 // TODO(youngki) add support for L2CAP sockets as well. | 95 return; |
72 | 96 } |
73 return scoped_refptr<BluetoothSocketWin>(bluetooth_socket); | 97 |
74 } | 98 socket_win_.reset(new net::TCPSocketWin(net_log_, source_)); |
75 | 99 net::EnsureWinsockInit(); |
76 bool BluetoothSocketWin::Receive(net::GrowableIOBuffer* buffer) { | 100 SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); |
77 buffer->SetCapacity(1024); | 101 SOCKADDR_BTH sa; |
78 int bytes_read; | 102 ZeroMemory(&sa, sizeof(sa)); |
79 do { | 103 sa.addressFamily = AF_BTH; |
80 if (buffer->RemainingCapacity() == 0) | 104 sa.port = rfcomm_channel_; |
81 buffer->SetCapacity(buffer->capacity() * 2); | 105 sa.btAddr = bth_addr_; |
82 bytes_read = recv(fd_, buffer->data(), buffer->RemainingCapacity(), 0); | 106 |
83 if (bytes_read > 0) | 107 // TODO(rpaquay): Condider making this call non-blocking. |
84 buffer->set_offset(buffer->offset() + bytes_read); | 108 int status = connect(socket_fd, reinterpret_cast<SOCKADDR*>(&sa), sizeof(sa)); |
85 } while (bytes_read > 0); | |
86 | |
87 DWORD error_code = WSAGetLastError(); | 109 DWORD error_code = WSAGetLastError(); |
88 if (bytes_read < 0 && error_code != WSAEWOULDBLOCK) { | 110 if (!(status == 0 || error_code == WSAEINPROGRESS)) { |
89 error_message_ = FormatErrorMessage(error_code); | 111 LOG(ERROR) << "Failed to connect bluetooth socket " |
90 return false; | 112 << "(" << device_address_ << "): " |
91 } | 113 << "(" << error_code << ")" << FormatErrorMessage(error_code); |
92 return true; | 114 error_callback.Run("Error connecting to socket: " + |
93 } | 115 FormatErrorMessage(error_code)); |
94 | 116 closesocket(socket_fd); |
95 bool BluetoothSocketWin::Send(net::DrainableIOBuffer* buffer) { | 117 return; |
96 int bytes_written; | 118 } |
97 do { | 119 |
98 bytes_written = send(fd_, buffer->data(), buffer->BytesRemaining(), 0); | 120 // Note: We don't have a meaningful |IPEndPoint|, but that is ok since the |
99 if (bytes_written > 0) | 121 // TCPSocketWin implementation does not actually require one. |
100 buffer->DidConsume(bytes_written); | 122 int net_result = |
101 } while (buffer->BytesRemaining() > 0 && bytes_written > 0); | 123 socket_win_->AdoptConnectedSocket(socket_fd, net::IPEndPoint()); |
102 | 124 if (net_result != net::OK) { |
103 DWORD error_code = WSAGetLastError(); | 125 error_callback.Run("Error connecting to socket: " + |
104 if (bytes_written < 0 && error_code != WSAEWOULDBLOCK) { | 126 std::string(net::ErrorToString(net_result))); |
105 error_message_ = FormatErrorMessage(error_code); | 127 closesocket(socket_fd); |
106 return false; | 128 return; |
107 } | 129 } |
108 return true; | 130 |
109 } | 131 success_callback.Run(); |
110 | 132 } |
111 std::string BluetoothSocketWin::GetLastErrorMessage() const { | 133 |
112 return error_message_; | 134 void BluetoothSocketWin::Disconnect(const base::Closure& success_callback) { |
| 135 DCHECK(thread_checker_.CalledOnValidThread()); |
| 136 base::ThreadRestrictions::AssertIOAllowed(); |
| 137 |
| 138 if (socket_win_) { |
| 139 socket_win_->Close(); |
| 140 socket_win_.reset(NULL); |
| 141 } |
| 142 |
| 143 // Note: Closing |socket_win_| above released all potential pending |
| 144 // Send/Receive operations, so we can no safely release the state associated |
| 145 // to those pending operations. |
| 146 read_buffer_ = NULL; |
| 147 std::queue<linked_ptr<WriteRequest> > empty; |
| 148 write_queue_.swap(empty); |
| 149 |
| 150 success_callback.Run(); |
| 151 } |
| 152 |
| 153 void BluetoothSocketWin::Receive( |
| 154 int count, |
| 155 const ReceiveCompletionCallback& success_callback, |
| 156 const ReceiveErrorCompletionCallback& error_callback) { |
| 157 DCHECK(thread_checker_.CalledOnValidThread()); |
| 158 base::ThreadRestrictions::AssertIOAllowed(); |
| 159 |
| 160 if (!socket_win_) { |
| 161 error_callback.Run(BluetoothSocketWin::kDisconnected, kSocketNotConnected); |
| 162 return; |
| 163 } |
| 164 |
| 165 // Only one pending read at a time |
| 166 if (read_buffer_.get()) { |
| 167 error_callback.Run(BluetoothSocketWin::kIOPending, |
| 168 net::ErrorToString(net::ERR_IO_PENDING)); |
| 169 return; |
| 170 } |
| 171 |
| 172 scoped_refptr<net::IOBufferWithSize> buffer(new net::IOBufferWithSize(count)); |
| 173 int read_result = |
| 174 socket_win_->Read(buffer.get(), |
| 175 buffer->size(), |
| 176 base::Bind(&BluetoothSocketWin::OnSocketReadComplete, |
| 177 this, |
| 178 success_callback, |
| 179 error_callback)); |
| 180 |
| 181 if (read_result > 0) { |
| 182 success_callback.Run(read_result, buffer); |
| 183 } else if (read_result == net::OK || |
| 184 read_result == net::ERR_CONNECTION_CLOSED) { |
| 185 error_callback.Run(BluetoothSocketWin::kDisconnected, |
| 186 net::ErrorToString(net::ERR_CONNECTION_CLOSED)); |
| 187 } else if (read_result == net::ERR_IO_PENDING) { |
| 188 read_buffer_ = buffer; |
| 189 } else { |
| 190 error_callback.Run(BluetoothSocketWin::kSystemError, |
| 191 net::ErrorToString(read_result)); |
| 192 } |
| 193 } |
| 194 |
| 195 void BluetoothSocketWin::OnSocketReadComplete( |
| 196 const ReceiveCompletionCallback& success_callback, |
| 197 const ReceiveErrorCompletionCallback& error_callback, |
| 198 int read_result) { |
| 199 DCHECK(thread_checker_.CalledOnValidThread()); |
| 200 base::ThreadRestrictions::AssertIOAllowed(); |
| 201 |
| 202 scoped_refptr<net::IOBufferWithSize> buffer; |
| 203 buffer.swap(read_buffer_); |
| 204 if (read_result > 0) { |
| 205 success_callback.Run(read_result, buffer); |
| 206 } else if (read_result == net::OK || |
| 207 read_result == net::ERR_CONNECTION_CLOSED) { |
| 208 error_callback.Run(BluetoothSocketWin::kDisconnected, |
| 209 net::ErrorToString(net::ERR_CONNECTION_CLOSED)); |
| 210 } else { |
| 211 error_callback.Run(BluetoothSocketWin::kSystemError, |
| 212 net::ErrorToString(read_result)); |
| 213 } |
| 214 } |
| 215 |
| 216 void BluetoothSocketWin::Send(scoped_refptr<net::DrainableIOBuffer> buffer, |
| 217 const SendCompletionCallback& success_callback, |
| 218 const ErrorCompletionCallback& error_callback) { |
| 219 DCHECK(thread_checker_.CalledOnValidThread()); |
| 220 base::ThreadRestrictions::AssertIOAllowed(); |
| 221 |
| 222 if (!socket_win_) { |
| 223 error_callback.Run(kSocketNotConnected); |
| 224 return; |
| 225 } |
| 226 |
| 227 linked_ptr<WriteRequest> request(new WriteRequest()); |
| 228 request->buffer = buffer; |
| 229 request->success_callback = success_callback; |
| 230 request->error_callback = error_callback; |
| 231 |
| 232 write_queue_.push(request); |
| 233 if (write_queue_.size() == 1) { |
| 234 SendFrontWriteRequest(); |
| 235 } |
| 236 } |
| 237 |
| 238 void BluetoothSocketWin::SendFrontWriteRequest() { |
| 239 DCHECK(thread_checker_.CalledOnValidThread()); |
| 240 base::ThreadRestrictions::AssertIOAllowed(); |
| 241 |
| 242 if (!socket_win_) |
| 243 return; |
| 244 |
| 245 if (write_queue_.size() == 0) |
| 246 return; |
| 247 |
| 248 linked_ptr<WriteRequest> request = write_queue_.front(); |
| 249 net::CompletionCallback callback = |
| 250 base::Bind(&BluetoothSocketWin::OnSocketWriteComplete, |
| 251 this, |
| 252 request->success_callback, |
| 253 request->error_callback); |
| 254 int send_result = |
| 255 socket_win_->Write(request->buffer, request->buffer->size(), callback); |
| 256 if (send_result != net::ERR_IO_PENDING) { |
| 257 callback.Run(send_result); |
| 258 } |
| 259 } |
| 260 |
| 261 void BluetoothSocketWin::OnSocketWriteComplete( |
| 262 const SendCompletionCallback& success_callback, |
| 263 const ErrorCompletionCallback& error_callback, |
| 264 int send_result) { |
| 265 DCHECK(thread_checker_.CalledOnValidThread()); |
| 266 base::ThreadRestrictions::AssertIOAllowed(); |
| 267 |
| 268 write_queue_.pop(); |
| 269 |
| 270 if (send_result >= net::OK) { |
| 271 success_callback.Run(send_result); |
| 272 } else { |
| 273 error_callback.Run(net::ErrorToString(send_result)); |
| 274 } |
| 275 |
| 276 // Don't call directly to avoid potentail large recursion. |
| 277 task_runner_->PostNonNestableTask( |
| 278 FROM_HERE, base::Bind(&BluetoothSocketWin::SendFrontWriteRequest, this)); |
113 } | 279 } |
114 | 280 |
115 } // namespace device | 281 } // namespace device |
OLD | NEW |