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"
11 #include "base/logging.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/sequenced_task_runner.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/sys_string_conversions.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/threading/thread_restrictions.h"
18 #include "device/bluetooth/bluetooth_device_win.h"
19 #include "device/bluetooth/bluetooth_init_win.h"
20 #include "device/bluetooth/bluetooth_service_record_win.h"
21 #include "device/bluetooth/bluetooth_socket_thread.h"
22 #include "net/base/io_buffer.h"
23 #include "net/base/ip_endpoint.h"
24 #include "net/base/net_errors.h"
25 #include "net/base/net_util.h"
26 #include "net/base/winsock_init.h"
30 const char kL2CAPNotSupported
[] = "Bluetooth L2CAP protocal is not supported";
31 const char kSocketAlreadyConnected
[] = "Socket is already connected.";
32 const char kInvalidRfcommPort
[] = "Invalid RFCCOMM port.";
33 const char kFailedToCreateSocket
[] = "Failed to create socket.";
34 const char kFailedToBindSocket
[] = "Failed to bind socket.";
35 const char kFailedToListenOnSocket
[] = "Failed to listen on socket.";
36 const char kFailedToGetSockNameForSocket
[] = "Failed to getsockname.";
37 const char kFailedToAccept
[] = "Failed to accept.";
38 const char kInvalidUUID
[] = "Invalid UUID";
39 const char kWsaSetServiceError
[] = "WSASetService error.";
41 std::string
IPEndPointToBluetoothAddress(const net::IPEndPoint
& end_point
) {
42 if (end_point
.address().size() != net::kBluetoothAddressSize
)
44 // The address is copied from BTH_ADDR field of SOCKADDR_BTH, which is a
45 // 64-bit ULONGLONG that stores Bluetooth address in little-endian. Print in
46 // reverse order to preserve the correct ordering.
47 return base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
48 end_point
.address()[5],
49 end_point
.address()[4],
50 end_point
.address()[3],
51 end_point
.address()[2],
52 end_point
.address()[1],
53 end_point
.address()[0]);
60 struct BluetoothSocketWin::ServiceRegData
{
62 ZeroMemory(&address
, sizeof(address
));
63 ZeroMemory(&address_info
, sizeof(address_info
));
64 ZeroMemory(&uuid
, sizeof(uuid
));
65 ZeroMemory(&service
, sizeof(service
));
69 CSADDR_INFO address_info
;
76 scoped_refptr
<BluetoothSocketWin
>
77 BluetoothSocketWin::CreateBluetoothSocket(
78 scoped_refptr
<base::SequencedTaskRunner
> ui_task_runner
,
79 scoped_refptr
<device::BluetoothSocketThread
> socket_thread
) {
80 DCHECK(ui_task_runner
->RunsTasksOnCurrentThread());
82 return make_scoped_refptr(
83 new BluetoothSocketWin(ui_task_runner
, socket_thread
));
86 BluetoothSocketWin::BluetoothSocketWin(
87 scoped_refptr
<base::SequencedTaskRunner
> ui_task_runner
,
88 scoped_refptr
<BluetoothSocketThread
> socket_thread
)
89 : BluetoothSocketNet(ui_task_runner
, socket_thread
),
90 supports_rfcomm_(false),
91 rfcomm_channel_(0xFF),
92 bth_addr_(BTH_ADDR_NULL
) {
95 BluetoothSocketWin::~BluetoothSocketWin() {
98 void BluetoothSocketWin::Connect(
99 const BluetoothDeviceWin
* device
,
100 const BluetoothUUID
& uuid
,
101 const base::Closure
& success_callback
,
102 const ErrorCompletionCallback
& error_callback
) {
103 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
106 if (!uuid
.IsValid()) {
107 error_callback
.Run(kInvalidUUID
);
111 const BluetoothServiceRecordWin
* service_record_win
=
112 device
->GetServiceRecord(uuid
);
113 if (!service_record_win
) {
114 error_callback
.Run(kInvalidUUID
);
118 device_address_
= service_record_win
->device_address();
119 if (service_record_win
->SupportsRfcomm()) {
120 supports_rfcomm_
= true;
121 rfcomm_channel_
= service_record_win
->rfcomm_channel();
122 bth_addr_
= service_record_win
->device_bth_addr();
125 socket_thread()->task_runner()->PostTask(
128 &BluetoothSocketWin::DoConnect
,
130 base::Bind(&BluetoothSocketWin::PostSuccess
, this, success_callback
),
132 &BluetoothSocketWin::PostErrorCompletion
, this, error_callback
)));
135 void BluetoothSocketWin::Listen(scoped_refptr
<BluetoothAdapter
> adapter
,
136 const BluetoothUUID
& uuid
,
137 const BluetoothAdapter::ServiceOptions
& options
,
138 const base::Closure
& success_callback
,
139 const ErrorCompletionCallback
& error_callback
) {
140 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
143 int rfcomm_channel
= options
.channel
? *options
.channel
: 0;
145 // TODO(xiyuan): Use |options.name|.
146 socket_thread()->task_runner()->PostTask(
148 base::Bind(&BluetoothSocketWin::DoListen
,
156 void BluetoothSocketWin::ResetData() {
157 if (service_reg_data_
) {
158 if (WSASetService(&service_reg_data_
->service
,RNRSERVICE_DELETE
, 0) ==
160 LOG(WARNING
) << "Failed to unregister service.";
162 service_reg_data_
.reset();
166 void BluetoothSocketWin::Accept(
167 const AcceptCompletionCallback
& success_callback
,
168 const ErrorCompletionCallback
& error_callback
) {
169 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
171 socket_thread()->task_runner()->PostTask(
173 base::Bind(&BluetoothSocketWin::DoAccept
,
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 scoped_ptr
<net::TCPSocket
> scoped_socket(
197 new net::TCPSocket(NULL
, net::NetLog::Source()));
198 net::EnsureWinsockInit();
199 SOCKET socket_fd
= socket(AF_BTH
, SOCK_STREAM
, BTHPROTO_RFCOMM
);
201 ZeroMemory(&sa
, sizeof(sa
));
202 sa
.addressFamily
= AF_BTH
;
203 sa
.port
= rfcomm_channel_
;
204 sa
.btAddr
= bth_addr_
;
206 // TODO(rpaquay): Condider making this call non-blocking.
207 int status
= connect(socket_fd
, reinterpret_cast<SOCKADDR
*>(&sa
), sizeof(sa
));
208 DWORD error_code
= WSAGetLastError();
209 if (!(status
== 0 || error_code
== WSAEINPROGRESS
)) {
210 LOG(ERROR
) << "Failed to connect bluetooth socket "
211 << "(" << device_address_
<< "): "
212 << logging::SystemErrorCodeToString(error_code
);
213 error_callback
.Run("Error connecting to socket: " +
214 logging::SystemErrorCodeToString(error_code
));
215 closesocket(socket_fd
);
219 // Note: We don't have a meaningful |IPEndPoint|, but that is ok since the
220 // TCPSocket implementation does not actually require one.
222 scoped_socket
->AdoptConnectedSocket(socket_fd
, net::IPEndPoint());
223 if (net_result
!= net::OK
) {
224 error_callback
.Run("Error connecting to socket: " +
225 net::ErrorToString(net_result
));
226 closesocket(socket_fd
);
230 SetTCPSocket(scoped_socket
.Pass());
231 success_callback
.Run();
234 void BluetoothSocketWin::DoListen(
235 const BluetoothUUID
& uuid
,
237 const base::Closure
& success_callback
,
238 const ErrorCompletionCallback
& error_callback
) {
239 DCHECK(socket_thread()->task_runner()->RunsTasksOnCurrentThread());
240 DCHECK(!tcp_socket() && !service_reg_data_
);
242 // The valid range is 0-30. 0 means BT_PORT_ANY and 1-30 are the
243 // valid RFCOMM port numbers of SOCKADDR_BTH.
244 if (rfcomm_channel
< 0 || rfcomm_channel
> 30) {
245 LOG(WARNING
) << "Failed to start service: "
246 << "Invalid RFCCOMM port " << rfcomm_channel
247 << ", uuid=" << uuid
.value();
248 PostErrorCompletion(error_callback
, kInvalidRfcommPort
);
252 SOCKET socket_fd
= socket(AF_BTH
, SOCK_STREAM
, BTHPROTO_RFCOMM
);
253 if (socket_fd
== INVALID_SOCKET
) {
254 LOG(WARNING
) << "Failed to start service: create socket, "
255 << "winsock err=" << WSAGetLastError();
256 PostErrorCompletion(error_callback
, kFailedToCreateSocket
);
260 // Note that |socket_fd| belongs to a non-TCP address family (i.e. AF_BTH),
261 // TCPSocket methods that involve address could not be called. So bind()
262 // is called on |socket_fd| directly.
263 scoped_ptr
<net::TCPSocket
> scoped_socket(
264 new net::TCPSocket(NULL
, net::NetLog::Source()));
265 scoped_socket
->AdoptListenSocket(socket_fd
);
268 struct sockaddr
* sock_addr
= reinterpret_cast<struct sockaddr
*>(&sa
);
269 int sock_addr_len
= sizeof(sa
);
270 ZeroMemory(&sa
, sock_addr_len
);
271 sa
.addressFamily
= AF_BTH
;
272 sa
.port
= rfcomm_channel
? rfcomm_channel
: BT_PORT_ANY
;
273 if (bind(socket_fd
, sock_addr
, sock_addr_len
) < 0) {
274 LOG(WARNING
) << "Failed to start service: create socket, "
275 << "winsock err=" << WSAGetLastError();
276 PostErrorCompletion(error_callback
, kFailedToBindSocket
);
280 const int kListenBacklog
= 5;
281 if (scoped_socket
->Listen(kListenBacklog
) < 0) {
282 LOG(WARNING
) << "Failed to start service: Listen"
283 << "winsock err=" << WSAGetLastError();
284 PostErrorCompletion(error_callback
, kFailedToListenOnSocket
);
288 scoped_ptr
<ServiceRegData
> reg_data(new ServiceRegData
);
289 reg_data
->name
= base::UTF8ToUTF16(uuid
.canonical_value());
291 if (getsockname(socket_fd
, sock_addr
, &sock_addr_len
)) {
292 LOG(WARNING
) << "Failed to start service: getsockname, "
293 << "winsock err=" << WSAGetLastError();
294 PostErrorCompletion(error_callback
, kFailedToGetSockNameForSocket
);
297 reg_data
->address
= sa
;
299 reg_data
->address_info
.LocalAddr
.iSockaddrLength
= sizeof(sa
);
300 reg_data
->address_info
.LocalAddr
.lpSockaddr
=
301 reinterpret_cast<struct sockaddr
*>(®_data
->address
);
302 reg_data
->address_info
.iSocketType
= SOCK_STREAM
;
303 reg_data
->address_info
.iProtocol
= BTHPROTO_RFCOMM
;
305 base::string16 cannonical_uuid
= L
"{" + base::ASCIIToUTF16(
306 uuid
.canonical_value()) + L
"}";
307 if (!SUCCEEDED(CLSIDFromString(cannonical_uuid
.c_str(), ®_data
->uuid
))) {
308 LOG(WARNING
) << "Failed to start service: "
309 << ", invalid uuid=" << cannonical_uuid
;
310 PostErrorCompletion(error_callback
, kInvalidUUID
);
314 reg_data
->service
.dwSize
= sizeof(WSAQUERYSET
);
315 reg_data
->service
.lpszServiceInstanceName
=
316 const_cast<LPWSTR
>(reg_data
->name
.c_str());
317 reg_data
->service
.lpServiceClassId
= ®_data
->uuid
;
318 reg_data
->service
.dwNameSpace
= NS_BTH
;
319 reg_data
->service
.dwNumberOfCsAddrs
= 1;
320 reg_data
->service
.lpcsaBuffer
= ®_data
->address_info
;
322 if (WSASetService(®_data
->service
,
323 RNRSERVICE_REGISTER
, 0) == SOCKET_ERROR
) {
324 LOG(WARNING
) << "Failed to register profile: WSASetService"
325 << "winsock err=" << WSAGetLastError();
326 PostErrorCompletion(error_callback
, kWsaSetServiceError
);
330 SetTCPSocket(scoped_socket
.Pass());
331 service_reg_data_
= reg_data
.Pass();
333 PostSuccess(success_callback
);
336 void BluetoothSocketWin::DoAccept(
337 const AcceptCompletionCallback
& success_callback
,
338 const ErrorCompletionCallback
& error_callback
) {
339 DCHECK(socket_thread()->task_runner()->RunsTasksOnCurrentThread());
340 int result
= tcp_socket()->Accept(
343 base::Bind(&BluetoothSocketWin::OnAcceptOnSocketThread
,
347 if (result
!= net::OK
&& result
!= net::ERR_IO_PENDING
) {
348 LOG(WARNING
) << "Failed to accept, net err=" << result
;
349 PostErrorCompletion(error_callback
, kFailedToAccept
);
353 void BluetoothSocketWin::OnAcceptOnSocketThread(
354 const AcceptCompletionCallback
& success_callback
,
355 const ErrorCompletionCallback
& error_callback
,
357 DCHECK(socket_thread()->task_runner()->RunsTasksOnCurrentThread());
358 if (accept_result
!= net::OK
) {
359 LOG(WARNING
) << "OnAccept error, net err=" << accept_result
;
360 PostErrorCompletion(error_callback
, kFailedToAccept
);
364 ui_task_runner()->PostTask(
366 base::Bind(&BluetoothSocketWin::OnAcceptOnUI
,
368 base::Passed(&accept_socket_
),
374 void BluetoothSocketWin::OnAcceptOnUI(
375 scoped_ptr
<net::TCPSocket
> accept_socket
,
376 const net::IPEndPoint
& peer_address
,
377 const AcceptCompletionCallback
& success_callback
,
378 const ErrorCompletionCallback
& error_callback
) {
379 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
381 const std::string peer_device_address
=
382 IPEndPointToBluetoothAddress(peer_address
);
383 const BluetoothDevice
* peer_device
= adapter_
->GetDevice(peer_device_address
);
385 LOG(WARNING
) << "OnAccept failed with unknown device, addr="
386 << peer_device_address
;
387 error_callback
.Run(kFailedToAccept
);
391 scoped_refptr
<BluetoothSocketWin
> peer_socket
=
392 CreateBluetoothSocket(ui_task_runner(), socket_thread());
393 peer_socket
->SetTCPSocket(accept_socket
.Pass());
394 success_callback
.Run(peer_device
, peer_socket
);
397 } // namespace device