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/winsock_init.h"
29 const char kL2CAPNotSupported
[] = "Bluetooth L2CAP protocal is not supported";
30 const char kSocketAlreadyConnected
[] = "Socket is already connected.";
31 const char kInvalidRfcommPort
[] = "Invalid RFCCOMM port.";
32 const char kFailedToCreateSocket
[] = "Failed to create socket.";
33 const char kFailedToBindSocket
[] = "Failed to bind socket.";
34 const char kFailedToListenOnSocket
[] = "Failed to listen on socket.";
35 const char kFailedToGetSockNameForSocket
[] = "Failed to getsockname.";
36 const char kFailedToAccept
[] = "Failed to accept.";
37 const char kInvalidUUID
[] = "Invalid UUID";
38 const char kWsaSetServiceError
[] = "WSASetService error.";
40 std::string
IPEndPointToBluetoothAddress(const net::IPEndPoint
& end_point
) {
41 if (end_point
.address().size() != net::kBluetoothAddressSize
)
43 // The address is copied from BTH_ADDR field of SOCKADDR_BTH, which is a
44 // 64-bit ULONGLONG that stores Bluetooth address in little-endian. Print in
45 // reverse order to preserve the correct ordering.
46 return base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
47 end_point
.address()[5],
48 end_point
.address()[4],
49 end_point
.address()[3],
50 end_point
.address()[2],
51 end_point
.address()[1],
52 end_point
.address()[0]);
59 struct BluetoothSocketWin::ServiceRegData
{
61 ZeroMemory(&address
, sizeof(address
));
62 ZeroMemory(&address_info
, sizeof(address_info
));
63 ZeroMemory(&uuid
, sizeof(uuid
));
64 ZeroMemory(&service
, sizeof(service
));
68 CSADDR_INFO address_info
;
75 scoped_refptr
<BluetoothSocketWin
>
76 BluetoothSocketWin::CreateBluetoothSocket(
77 scoped_refptr
<base::SequencedTaskRunner
> ui_task_runner
,
78 scoped_refptr
<device::BluetoothSocketThread
> socket_thread
) {
79 DCHECK(ui_task_runner
->RunsTasksOnCurrentThread());
81 return make_scoped_refptr(
82 new BluetoothSocketWin(ui_task_runner
, socket_thread
));
85 BluetoothSocketWin::BluetoothSocketWin(
86 scoped_refptr
<base::SequencedTaskRunner
> ui_task_runner
,
87 scoped_refptr
<BluetoothSocketThread
> socket_thread
)
88 : BluetoothSocketNet(ui_task_runner
, socket_thread
),
89 supports_rfcomm_(false),
90 rfcomm_channel_(0xFF),
91 bth_addr_(BTH_ADDR_NULL
) {
94 BluetoothSocketWin::~BluetoothSocketWin() {
97 void BluetoothSocketWin::Connect(
98 const BluetoothDeviceWin
* device
,
99 const BluetoothUUID
& uuid
,
100 const base::Closure
& success_callback
,
101 const ErrorCompletionCallback
& error_callback
) {
102 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
105 if (!uuid
.IsValid()) {
106 error_callback
.Run(kInvalidUUID
);
110 const BluetoothServiceRecordWin
* service_record_win
=
111 device
->GetServiceRecord(uuid
);
112 if (!service_record_win
) {
113 error_callback
.Run(kInvalidUUID
);
117 device_address_
= service_record_win
->device_address();
118 if (service_record_win
->SupportsRfcomm()) {
119 supports_rfcomm_
= true;
120 rfcomm_channel_
= service_record_win
->rfcomm_channel();
121 bth_addr_
= service_record_win
->device_bth_addr();
124 socket_thread()->task_runner()->PostTask(
127 &BluetoothSocketWin::DoConnect
,
129 base::Bind(&BluetoothSocketWin::PostSuccess
, this, success_callback
),
131 &BluetoothSocketWin::PostErrorCompletion
, this, error_callback
)));
134 void BluetoothSocketWin::Listen(scoped_refptr
<BluetoothAdapter
> adapter
,
135 const BluetoothUUID
& uuid
,
136 const BluetoothAdapter::ServiceOptions
& options
,
137 const base::Closure
& success_callback
,
138 const ErrorCompletionCallback
& error_callback
) {
139 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
142 int rfcomm_channel
= options
.channel
? *options
.channel
: 0;
144 // TODO(xiyuan): Use |options.name|.
145 socket_thread()->task_runner()->PostTask(
147 base::Bind(&BluetoothSocketWin::DoListen
,
155 void BluetoothSocketWin::ResetData() {
156 if (service_reg_data_
) {
157 if (WSASetService(&service_reg_data_
->service
,RNRSERVICE_DELETE
, 0) ==
159 LOG(WARNING
) << "Failed to unregister service.";
161 service_reg_data_
.reset();
165 void BluetoothSocketWin::Accept(
166 const AcceptCompletionCallback
& success_callback
,
167 const ErrorCompletionCallback
& error_callback
) {
168 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
170 socket_thread()->task_runner()->PostTask(
172 base::Bind(&BluetoothSocketWin::DoAccept
,
178 void BluetoothSocketWin::DoConnect(
179 const base::Closure
& success_callback
,
180 const ErrorCompletionCallback
& error_callback
) {
181 DCHECK(socket_thread()->task_runner()->RunsTasksOnCurrentThread());
182 base::ThreadRestrictions::AssertIOAllowed();
185 error_callback
.Run(kSocketAlreadyConnected
);
189 if (!supports_rfcomm_
) {
190 // TODO(youngki) add support for L2CAP sockets as well.
191 error_callback
.Run(kL2CAPNotSupported
);
195 scoped_ptr
<net::TCPSocket
> scoped_socket(
196 new net::TCPSocket(NULL
, net::NetLog::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 << logging::SystemErrorCodeToString(error_code
);
212 error_callback
.Run("Error connecting to socket: " +
213 logging::SystemErrorCodeToString(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 scoped_socket
->AdoptConnectedSocket(socket_fd
, net::IPEndPoint());
222 if (net_result
!= net::OK
) {
223 error_callback
.Run("Error connecting to socket: " +
224 net::ErrorToString(net_result
));
225 closesocket(socket_fd
);
229 SetTCPSocket(scoped_socket
.Pass());
230 success_callback
.Run();
233 void BluetoothSocketWin::DoListen(
234 const BluetoothUUID
& uuid
,
236 const base::Closure
& success_callback
,
237 const ErrorCompletionCallback
& error_callback
) {
238 DCHECK(socket_thread()->task_runner()->RunsTasksOnCurrentThread());
239 DCHECK(!tcp_socket() && !service_reg_data_
);
241 // The valid range is 0-30. 0 means BT_PORT_ANY and 1-30 are the
242 // valid RFCOMM port numbers of SOCKADDR_BTH.
243 if (rfcomm_channel
< 0 || rfcomm_channel
> 30) {
244 LOG(WARNING
) << "Failed to start service: "
245 << "Invalid RFCCOMM port " << rfcomm_channel
246 << ", uuid=" << uuid
.value();
247 PostErrorCompletion(error_callback
, kInvalidRfcommPort
);
251 SOCKET socket_fd
= socket(AF_BTH
, SOCK_STREAM
, BTHPROTO_RFCOMM
);
252 if (socket_fd
== INVALID_SOCKET
) {
253 LOG(WARNING
) << "Failed to start service: create socket, "
254 << "winsock err=" << WSAGetLastError();
255 PostErrorCompletion(error_callback
, kFailedToCreateSocket
);
259 // Note that |socket_fd| belongs to a non-TCP address family (i.e. AF_BTH),
260 // TCPSocket methods that involve address could not be called. So bind()
261 // is called on |socket_fd| directly.
262 scoped_ptr
<net::TCPSocket
> scoped_socket(
263 new net::TCPSocket(NULL
, net::NetLog::Source()));
264 scoped_socket
->AdoptListenSocket(socket_fd
);
267 struct sockaddr
* sock_addr
= reinterpret_cast<struct sockaddr
*>(&sa
);
268 int sock_addr_len
= sizeof(sa
);
269 ZeroMemory(&sa
, sock_addr_len
);
270 sa
.addressFamily
= AF_BTH
;
271 sa
.port
= rfcomm_channel
? rfcomm_channel
: BT_PORT_ANY
;
272 if (bind(socket_fd
, sock_addr
, sock_addr_len
) < 0) {
273 LOG(WARNING
) << "Failed to start service: create socket, "
274 << "winsock err=" << WSAGetLastError();
275 PostErrorCompletion(error_callback
, kFailedToBindSocket
);
279 const int kListenBacklog
= 5;
280 if (scoped_socket
->Listen(kListenBacklog
) < 0) {
281 LOG(WARNING
) << "Failed to start service: Listen"
282 << "winsock err=" << WSAGetLastError();
283 PostErrorCompletion(error_callback
, kFailedToListenOnSocket
);
287 scoped_ptr
<ServiceRegData
> reg_data(new ServiceRegData
);
288 reg_data
->name
= base::UTF8ToUTF16(uuid
.canonical_value());
290 if (getsockname(socket_fd
, sock_addr
, &sock_addr_len
)) {
291 LOG(WARNING
) << "Failed to start service: getsockname, "
292 << "winsock err=" << WSAGetLastError();
293 PostErrorCompletion(error_callback
, kFailedToGetSockNameForSocket
);
296 reg_data
->address
= sa
;
298 reg_data
->address_info
.LocalAddr
.iSockaddrLength
= sizeof(sa
);
299 reg_data
->address_info
.LocalAddr
.lpSockaddr
=
300 reinterpret_cast<struct sockaddr
*>(®_data
->address
);
301 reg_data
->address_info
.iSocketType
= SOCK_STREAM
;
302 reg_data
->address_info
.iProtocol
= BTHPROTO_RFCOMM
;
304 base::string16 cannonical_uuid
= L
"{" + base::ASCIIToUTF16(
305 uuid
.canonical_value()) + L
"}";
306 if (!SUCCEEDED(CLSIDFromString(cannonical_uuid
.c_str(), ®_data
->uuid
))) {
307 LOG(WARNING
) << "Failed to start service: "
308 << ", invalid uuid=" << cannonical_uuid
;
309 PostErrorCompletion(error_callback
, kInvalidUUID
);
313 reg_data
->service
.dwSize
= sizeof(WSAQUERYSET
);
314 reg_data
->service
.lpszServiceInstanceName
=
315 const_cast<LPWSTR
>(reg_data
->name
.c_str());
316 reg_data
->service
.lpServiceClassId
= ®_data
->uuid
;
317 reg_data
->service
.dwNameSpace
= NS_BTH
;
318 reg_data
->service
.dwNumberOfCsAddrs
= 1;
319 reg_data
->service
.lpcsaBuffer
= ®_data
->address_info
;
321 if (WSASetService(®_data
->service
,
322 RNRSERVICE_REGISTER
, 0) == SOCKET_ERROR
) {
323 LOG(WARNING
) << "Failed to register profile: WSASetService"
324 << "winsock err=" << WSAGetLastError();
325 PostErrorCompletion(error_callback
, kWsaSetServiceError
);
329 SetTCPSocket(scoped_socket
.Pass());
330 service_reg_data_
= reg_data
.Pass();
332 PostSuccess(success_callback
);
335 void BluetoothSocketWin::DoAccept(
336 const AcceptCompletionCallback
& success_callback
,
337 const ErrorCompletionCallback
& error_callback
) {
338 DCHECK(socket_thread()->task_runner()->RunsTasksOnCurrentThread());
339 int result
= tcp_socket()->Accept(
342 base::Bind(&BluetoothSocketWin::OnAcceptOnSocketThread
,
346 if (result
!= net::OK
&& result
!= net::ERR_IO_PENDING
) {
347 LOG(WARNING
) << "Failed to accept, net err=" << result
;
348 PostErrorCompletion(error_callback
, kFailedToAccept
);
352 void BluetoothSocketWin::OnAcceptOnSocketThread(
353 const AcceptCompletionCallback
& success_callback
,
354 const ErrorCompletionCallback
& error_callback
,
356 DCHECK(socket_thread()->task_runner()->RunsTasksOnCurrentThread());
357 if (accept_result
!= net::OK
) {
358 LOG(WARNING
) << "OnAccept error, net err=" << accept_result
;
359 PostErrorCompletion(error_callback
, kFailedToAccept
);
363 ui_task_runner()->PostTask(
365 base::Bind(&BluetoothSocketWin::OnAcceptOnUI
,
367 base::Passed(&accept_socket_
),
373 void BluetoothSocketWin::OnAcceptOnUI(
374 scoped_ptr
<net::TCPSocket
> accept_socket
,
375 const net::IPEndPoint
& peer_address
,
376 const AcceptCompletionCallback
& success_callback
,
377 const ErrorCompletionCallback
& error_callback
) {
378 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
380 const std::string peer_device_address
=
381 IPEndPointToBluetoothAddress(peer_address
);
382 const BluetoothDevice
* peer_device
= adapter_
->GetDevice(peer_device_address
);
384 LOG(WARNING
) << "OnAccept failed with unknown device, addr="
385 << peer_device_address
;
386 error_callback
.Run(kFailedToAccept
);
390 scoped_refptr
<BluetoothSocketWin
> peer_socket
=
391 CreateBluetoothSocket(ui_task_runner(), socket_thread());
392 peer_socket
->SetTCPSocket(accept_socket
.Pass());
393 success_callback
.Run(peer_device
, peer_socket
);
396 } // namespace device