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 |