Enable Cast in ChromePublic
[chromium-blink-merge.git] / device / bluetooth / bluetooth_socket_win.cc
blobdfa695106959dfb465f031920acf54e795b196f5
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"
7 #include <objbase.h>
9 #include <string>
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"
28 namespace {
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)
43 return std::string();
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]);
56 } // namespace
58 namespace device {
60 struct BluetoothSocketWin::ServiceRegData {
61 ServiceRegData() {
62 ZeroMemory(&address, sizeof(address));
63 ZeroMemory(&address_info, sizeof(address_info));
64 ZeroMemory(&uuid, sizeof(uuid));
65 ZeroMemory(&service, sizeof(service));
68 SOCKADDR_BTH address;
69 CSADDR_INFO address_info;
70 GUID uuid;
71 base::string16 name;
72 WSAQUERYSET service;
75 // static
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());
104 DCHECK(device);
106 if (!uuid.IsValid()) {
107 error_callback.Run(kInvalidUUID);
108 return;
111 const BluetoothServiceRecordWin* service_record_win =
112 device->GetServiceRecord(uuid);
113 if (!service_record_win) {
114 error_callback.Run(kInvalidUUID);
115 return;
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(
126 FROM_HERE,
127 base::Bind(
128 &BluetoothSocketWin::DoConnect,
129 this,
130 base::Bind(&BluetoothSocketWin::PostSuccess, this, success_callback),
131 base::Bind(
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());
142 adapter_ = adapter;
143 int rfcomm_channel = options.channel ? *options.channel : 0;
145 // TODO(xiyuan): Use |options.name|.
146 socket_thread()->task_runner()->PostTask(
147 FROM_HERE,
148 base::Bind(&BluetoothSocketWin::DoListen,
149 this,
150 uuid,
151 rfcomm_channel,
152 success_callback,
153 error_callback));
156 void BluetoothSocketWin::ResetData() {
157 if (service_reg_data_) {
158 if (WSASetService(&service_reg_data_->service,RNRSERVICE_DELETE, 0) ==
159 SOCKET_ERROR) {
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(
172 FROM_HERE,
173 base::Bind(&BluetoothSocketWin::DoAccept,
174 this,
175 success_callback,
176 error_callback));
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();
185 if (tcp_socket()) {
186 error_callback.Run(kSocketAlreadyConnected);
187 return;
190 if (!supports_rfcomm_) {
191 // TODO(youngki) add support for L2CAP sockets as well.
192 error_callback.Run(kL2CAPNotSupported);
193 return;
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);
200 SOCKADDR_BTH sa;
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);
216 return;
219 // Note: We don't have a meaningful |IPEndPoint|, but that is ok since the
220 // TCPSocket implementation does not actually require one.
221 int net_result =
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);
227 return;
230 SetTCPSocket(scoped_socket.Pass());
231 success_callback.Run();
234 void BluetoothSocketWin::DoListen(
235 const BluetoothUUID& uuid,
236 int rfcomm_channel,
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);
249 return;
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);
257 return;
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);
267 SOCKADDR_BTH sa;
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);
277 return;
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);
285 return;
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);
295 return;
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*>(&reg_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(), &reg_data->uuid))) {
308 LOG(WARNING) << "Failed to start service: "
309 << ", invalid uuid=" << cannonical_uuid;
310 PostErrorCompletion(error_callback, kInvalidUUID);
311 return;
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 = &reg_data->uuid;
318 reg_data->service.dwNameSpace = NS_BTH;
319 reg_data->service.dwNumberOfCsAddrs = 1;
320 reg_data->service.lpcsaBuffer = &reg_data->address_info;
322 if (WSASetService(&reg_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);
327 return;
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(
341 &accept_socket_,
342 &accept_address_,
343 base::Bind(&BluetoothSocketWin::OnAcceptOnSocketThread,
344 this,
345 success_callback,
346 error_callback));
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,
356 int accept_result) {
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);
361 return;
364 ui_task_runner()->PostTask(
365 FROM_HERE,
366 base::Bind(&BluetoothSocketWin::OnAcceptOnUI,
367 this,
368 base::Passed(&accept_socket_),
369 accept_address_,
370 success_callback,
371 error_callback));
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);
384 if (!peer_device) {
385 LOG(WARNING) << "OnAccept failed with unknown device, addr="
386 << peer_device_address;
387 error_callback.Run(kFailedToAccept);
388 return;
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