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
3 // found in the LICENSE file.
5 #include "device/bluetooth/bluetooth_socket_win.h"
9 #include "base/logging.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/sequenced_task_runner.h"
12 #include "base/strings/sys_string_conversions.h"
13 #include "base/threading/thread_restrictions.h"
14 #include "device/bluetooth/bluetooth_init_win.h"
15 #include "device/bluetooth/bluetooth_service_record_win.h"
16 #include "device/bluetooth/bluetooth_socket_thread_win.h"
17 #include "net/base/io_buffer.h"
18 #include "net/base/ip_endpoint.h"
19 #include "net/base/net_errors.h"
20 #include "net/base/winsock_init.h"
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.";
28 using device::BluetoothSocketWin
;
30 std::string
FormatErrorMessage(DWORD error_code
) {
31 TCHAR error_msg
[1024];
32 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
,
39 return base::SysWideToUTF8(error_msg
);
42 static void DeactivateSocket(
43 const scoped_refptr
<device::BluetoothSocketThreadWin
>& socket_thread
) {
44 socket_thread
->OnSocketDeactivate();
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
,
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
);
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();
74 BluetoothSocketWin::BluetoothSocketWin(
75 scoped_refptr
<base::SequencedTaskRunner
> ui_task_runner
,
76 scoped_refptr
<BluetoothSocketThreadWin
> socket_thread
,
78 const net::NetLog::Source
& source
)
79 : ui_task_runner_(ui_task_runner
),
80 socket_thread_(socket_thread
),
83 supports_rfcomm_(false),
85 bth_addr_(BTH_ADDR_NULL
) {
86 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
87 socket_thread
->OnSocketActivate();
90 BluetoothSocketWin::~BluetoothSocketWin() {
91 ui_task_runner_
->PostTask(FROM_HERE
,
92 base::Bind(&DeactivateSocket
, socket_thread_
));
95 void BluetoothSocketWin::Close() {
96 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
97 socket_thread_
->task_runner()->PostTask(
98 FROM_HERE
, base::Bind(&BluetoothSocketWin::DoClose
, this));
101 void BluetoothSocketWin::Connect(
102 const base::Closure
& success_callback
,
103 const ErrorCompletionCallback
& error_callback
) {
104 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
105 socket_thread_
->task_runner()->PostTask(
108 &BluetoothSocketWin::DoConnect
,
110 base::Bind(&BluetoothSocketWin::PostSuccess
, this, success_callback
),
112 &BluetoothSocketWin::PostErrorCompletion
, this, error_callback
)));
115 void BluetoothSocketWin::Disconnect(const base::Closure
& success_callback
) {
116 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
117 socket_thread_
->task_runner()->PostTask(
120 &BluetoothSocketWin::DoDisconnect
,
123 &BluetoothSocketWin::PostSuccess
, this, success_callback
)));
126 void BluetoothSocketWin::Receive(
128 const ReceiveCompletionCallback
& success_callback
,
129 const ReceiveErrorCompletionCallback
& error_callback
) {
130 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
131 socket_thread_
->task_runner()->PostTask(
133 base::Bind(&BluetoothSocketWin::DoReceive
,
136 base::Bind(&BluetoothSocketWin::PostReceiveCompletion
,
139 base::Bind(&BluetoothSocketWin::PostReceiveErrorCompletion
,
144 void BluetoothSocketWin::Send(scoped_refptr
<net::IOBuffer
> buffer
,
146 const SendCompletionCallback
& success_callback
,
147 const ErrorCompletionCallback
& error_callback
) {
148 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
149 socket_thread_
->task_runner()->PostTask(
152 &BluetoothSocketWin::DoSend
,
157 &BluetoothSocketWin::PostSendCompletion
, this, success_callback
),
159 &BluetoothSocketWin::PostErrorCompletion
, this, error_callback
)));
162 void BluetoothSocketWin::DoClose() {
163 DCHECK(socket_thread_
->task_runner()->RunsTasksOnCurrentThread());
164 base::ThreadRestrictions::AssertIOAllowed();
167 tcp_socket_
->Close();
168 tcp_socket_
.reset(NULL
);
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.
175 std::queue
<linked_ptr
<WriteRequest
> > empty
;
176 write_queue_
.swap(empty
);
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();
186 error_callback
.Run(kSocketAlreadyConnected
);
190 if (!supports_rfcomm_
) {
191 // TODO(youngki) add support for L2CAP sockets as well.
192 error_callback
.Run(kL2CAPNotSupported
);
196 tcp_socket_
.reset(new net::TCPSocket(net_log_
, source_
));
197 net::EnsureWinsockInit();
198 SOCKET socket_fd
= socket(AF_BTH
, SOCK_STREAM
, BTHPROTO_RFCOMM
);
200 ZeroMemory(&sa
, sizeof(sa
));
201 sa
.addressFamily
= AF_BTH
;
202 sa
.port
= rfcomm_channel_
;
203 sa
.btAddr
= bth_addr_
;
205 // TODO(rpaquay): Condider making this call non-blocking.
206 int status
= connect(socket_fd
, reinterpret_cast<SOCKADDR
*>(&sa
), sizeof(sa
));
207 DWORD error_code
= WSAGetLastError();
208 if (!(status
== 0 || error_code
== WSAEINPROGRESS
)) {
209 LOG(ERROR
) << "Failed to connect bluetooth socket "
210 << "(" << device_address_
<< "): "
211 << "(" << error_code
<< ")" << FormatErrorMessage(error_code
);
212 error_callback
.Run("Error connecting to socket: " +
213 FormatErrorMessage(error_code
));
214 closesocket(socket_fd
);
218 // Note: We don't have a meaningful |IPEndPoint|, but that is ok since the
219 // TCPSocket implementation does not actually require one.
221 tcp_socket_
->AdoptConnectedSocket(socket_fd
, net::IPEndPoint());
222 if (net_result
!= net::OK
) {
223 error_callback
.Run("Error connecting to socket: " +
224 std::string(net::ErrorToString(net_result
)));
225 closesocket(socket_fd
);
229 success_callback
.Run();
232 void BluetoothSocketWin::DoDisconnect(const base::Closure
& success_callback
) {
233 DCHECK(socket_thread_
->task_runner()->RunsTasksOnCurrentThread());
234 base::ThreadRestrictions::AssertIOAllowed();
237 success_callback
.Run();
240 void BluetoothSocketWin::DoReceive(
242 const ReceiveCompletionCallback
& success_callback
,
243 const ReceiveErrorCompletionCallback
& error_callback
) {
244 DCHECK(socket_thread_
->task_runner()->RunsTasksOnCurrentThread());
245 base::ThreadRestrictions::AssertIOAllowed();
248 error_callback
.Run(BluetoothSocketWin::kDisconnected
, kSocketNotConnected
);
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
));
259 scoped_refptr
<net::IOBufferWithSize
> buffer(new net::IOBufferWithSize(count
));
261 tcp_socket_
->Read(buffer
.get(),
263 base::Bind(&BluetoothSocketWin::OnSocketReadComplete
,
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
;
277 error_callback
.Run(BluetoothSocketWin::kSystemError
,
278 net::ErrorToString(read_result
));
282 void BluetoothSocketWin::OnSocketReadComplete(
283 const ReceiveCompletionCallback
& success_callback
,
284 const ReceiveErrorCompletionCallback
& error_callback
,
286 DCHECK(socket_thread_
->task_runner()->RunsTasksOnCurrentThread());
287 base::ThreadRestrictions::AssertIOAllowed();
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
));
298 error_callback
.Run(BluetoothSocketWin::kSystemError
,
299 net::ErrorToString(read_result
));
303 void BluetoothSocketWin::DoSend(scoped_refptr
<net::IOBuffer
> buffer
,
305 const SendCompletionCallback
& success_callback
,
306 const ErrorCompletionCallback
& error_callback
) {
307 DCHECK(socket_thread_
->task_runner()->RunsTasksOnCurrentThread());
308 base::ThreadRestrictions::AssertIOAllowed();
311 error_callback
.Run(kSocketNotConnected
);
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
;
321 write_queue_
.push(request
);
322 if (write_queue_
.size() == 1) {
323 SendFrontWriteRequest();
327 void BluetoothSocketWin::SendFrontWriteRequest() {
328 DCHECK(socket_thread_
->task_runner()->RunsTasksOnCurrentThread());
329 base::ThreadRestrictions::AssertIOAllowed();
334 if (write_queue_
.size() == 0)
337 linked_ptr
<WriteRequest
> request
= write_queue_
.front();
338 net::CompletionCallback callback
=
339 base::Bind(&BluetoothSocketWin::OnSocketWriteComplete
,
341 request
->success_callback
,
342 request
->error_callback
);
344 tcp_socket_
->Write(request
->buffer
, request
->buffer_size
, callback
);
345 if (send_result
!= net::ERR_IO_PENDING
) {
346 callback
.Run(send_result
);
350 void BluetoothSocketWin::OnSocketWriteComplete(
351 const SendCompletionCallback
& success_callback
,
352 const ErrorCompletionCallback
& error_callback
,
354 DCHECK(socket_thread_
->task_runner()->RunsTasksOnCurrentThread());
355 base::ThreadRestrictions::AssertIOAllowed();
359 if (send_result
>= net::OK
) {
360 success_callback
.Run(send_result
);
362 error_callback
.Run(net::ErrorToString(send_result
));
365 // Don't call directly to avoid potentail large recursion.
366 socket_thread_
->task_runner()->PostNonNestableTask(
367 FROM_HERE
, base::Bind(&BluetoothSocketWin::SendFrontWriteRequest
, this));
370 void BluetoothSocketWin::PostSuccess(const base::Closure
& callback
) {
371 ui_task_runner_
->PostTask(FROM_HERE
, callback
);
374 void BluetoothSocketWin::PostErrorCompletion(
375 const ErrorCompletionCallback
& callback
,
376 const std::string
& error
) {
377 ui_task_runner_
->PostTask(FROM_HERE
, base::Bind(callback
, error
));
380 void BluetoothSocketWin::PostReceiveCompletion(
381 const ReceiveCompletionCallback
& callback
,
383 scoped_refptr
<net::IOBuffer
> io_buffer
) {
384 ui_task_runner_
->PostTask(FROM_HERE
,
385 base::Bind(callback
, io_buffer_size
, io_buffer
));
388 void BluetoothSocketWin::PostReceiveErrorCompletion(
389 const ReceiveErrorCompletionCallback
& callback
,
391 const std::string
& error_message
) {
392 ui_task_runner_
->PostTask(FROM_HERE
,
393 base::Bind(callback
, reason
, error_message
));
396 void BluetoothSocketWin::PostSendCompletion(
397 const SendCompletionCallback
& callback
,
399 ui_task_runner_
->PostTask(FROM_HERE
, base::Bind(callback
, bytes_written
));
402 } // namespace device