15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "device/bluetooth/bluetooth_socket_win.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include <objbase.h>
85c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string>
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/ref_counted.h"
13c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/sequenced_task_runner.h"
1446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/strings/stringprintf.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h"
165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/strings/utf_string_conversions.h"
17c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/threading/thread_restrictions.h"
1846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "device/bluetooth/bluetooth_device_win.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "device/bluetooth/bluetooth_init_win.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "device/bluetooth/bluetooth_service_record_win.h"
21010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "device/bluetooth/bluetooth_socket_thread.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/io_buffer.h"
23c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "net/base/ip_endpoint.h"
24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "net/base/net_errors.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/winsock_init.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
29c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst char kL2CAPNotSupported[] = "Bluetooth L2CAP protocal is not supported";
30c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst char kSocketAlreadyConnected[] = "Socket is already connected.";
315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst char kInvalidRfcommPort[] = "Invalid RFCCOMM port.";
325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst char kFailedToCreateSocket[] = "Failed to create socket.";
335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst char kFailedToBindSocket[] = "Failed to bind socket.";
345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst char kFailedToListenOnSocket[] = "Failed to listen on socket.";
355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst char kFailedToGetSockNameForSocket[] = "Failed to getsockname.";
3646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const char kFailedToAccept[] = "Failed to accept.";
3746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const char kInvalidUUID[] = "Invalid UUID";
385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst char kWsaSetServiceError[] = "WSASetService error.";
39c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
4046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)std::string IPEndPointToBluetoothAddress(const net::IPEndPoint& end_point) {
4146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (end_point.address().size() != net::kBluetoothAddressSize)
4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return std::string();
4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // The address is copied from BTH_ADDR field of SOCKADDR_BTH, which is a
4446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // 64-bit ULONGLONG that stores Bluetooth address in little-endian. Print in
4546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // reverse order to preserve the correct ordering.
4646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
4746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      end_point.address()[5],
4846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      end_point.address()[4],
4946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      end_point.address()[3],
5046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      end_point.address()[2],
5146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      end_point.address()[1],
5246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      end_point.address()[0]);
5346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
5446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace device {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liustruct BluetoothSocketWin::ServiceRegData {
605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ServiceRegData() {
615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    ZeroMemory(&address, sizeof(address));
625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    ZeroMemory(&address_info, sizeof(address_info));
635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    ZeroMemory(&uuid, sizeof(uuid));
645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    ZeroMemory(&service, sizeof(service));
655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  SOCKADDR_BTH address;
685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  CSADDR_INFO address_info;
695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  GUID uuid;
705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::string16 name;
715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  WSAQUERYSET service;
725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu};
735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
74c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// static
75010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)scoped_refptr<BluetoothSocketWin>
76010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)BluetoothSocketWin::CreateBluetoothSocket(
77c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_refptr<device::BluetoothSocketThread> socket_thread) {
79c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
80c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return make_scoped_refptr(
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      new BluetoothSocketWin(ui_task_runner, socket_thread));
83c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
84c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
85c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochBluetoothSocketWin::BluetoothSocketWin(
86c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_refptr<BluetoothSocketThread> socket_thread)
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : BluetoothSocketNet(ui_task_runner, socket_thread),
89c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      supports_rfcomm_(false),
90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      rfcomm_channel_(0xFF),
91c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      bth_addr_(BTH_ADDR_NULL) {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BluetoothSocketWin::~BluetoothSocketWin() {
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
97c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid BluetoothSocketWin::Connect(
9846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const BluetoothDeviceWin* device,
9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const BluetoothUUID& uuid,
100c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const base::Closure& success_callback,
101c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const ErrorCompletionCallback& error_callback) {
102010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
10346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(device);
10446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
10546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!uuid.IsValid()) {
10646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    error_callback.Run(kInvalidUUID);
10746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
10846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  const BluetoothServiceRecordWin* service_record_win =
11146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      device->GetServiceRecord(uuid);
11246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!service_record_win) {
11346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    error_callback.Run(kInvalidUUID);
11446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
11546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
11646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  device_address_ = service_record_win->device_address();
11846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (service_record_win->SupportsRfcomm()) {
1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    supports_rfcomm_ = true;
1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    rfcomm_channel_ = service_record_win->rfcomm_channel();
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bth_addr_ = service_record_win->device_bth_addr();
1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
124010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  socket_thread()->task_runner()->PostTask(
125c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      FROM_HERE,
126c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::Bind(
127c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          &BluetoothSocketWin::DoConnect,
128c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          this,
129c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          base::Bind(&BluetoothSocketWin::PostSuccess, this, success_callback),
130c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          base::Bind(
131c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch              &BluetoothSocketWin::PostErrorCompletion, this, error_callback)));
132c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
133c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
13446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void BluetoothSocketWin::Listen(scoped_refptr<BluetoothAdapter> adapter,
13546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                const BluetoothUUID& uuid,
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                const BluetoothAdapter::ServiceOptions& options,
13746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                const base::Closure& success_callback,
13846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                const ErrorCompletionCallback& error_callback) {
13946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
14046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
14146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  adapter_ = adapter;
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int rfcomm_channel = options.channel ? *options.channel : 0;
14346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // TODO(xiyuan): Use |options.name|.
14546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  socket_thread()->task_runner()->PostTask(
14646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      FROM_HERE,
14746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::Bind(&BluetoothSocketWin::DoListen,
14846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 this,
14946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 uuid,
15046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 rfcomm_channel,
15146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 success_callback,
15246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 error_callback));
15346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
1545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
155010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void BluetoothSocketWin::ResetData() {
1565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (service_reg_data_) {
1575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (WSASetService(&service_reg_data_->service,RNRSERVICE_DELETE, 0) ==
1585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        SOCKET_ERROR) {
1595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      LOG(WARNING) << "Failed to unregister service.";
1605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
1615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    service_reg_data_.reset();
1625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothSocketWin::Accept(
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const AcceptCompletionCallback& success_callback,
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const ErrorCompletionCallback& error_callback) {
16846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
16946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
17046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  socket_thread()->task_runner()->PostTask(
17146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      FROM_HERE,
17246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::Bind(&BluetoothSocketWin::DoAccept,
17346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 this,
17446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 success_callback,
17546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 error_callback));
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
178c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid BluetoothSocketWin::DoConnect(
179c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const base::Closure& success_callback,
180c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const ErrorCompletionCallback& error_callback) {
181010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(socket_thread()->task_runner()->RunsTasksOnCurrentThread());
182c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  base::ThreadRestrictions::AssertIOAllowed();
183c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
184010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (tcp_socket()) {
185c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    error_callback.Run(kSocketAlreadyConnected);
186c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
187c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
188c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
189c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!supports_rfcomm_) {
190c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // TODO(youngki) add support for L2CAP sockets as well.
191c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    error_callback.Run(kL2CAPNotSupported);
192c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
193c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
194c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<net::TCPSocket> scoped_socket(
1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      new net::TCPSocket(NULL, net::NetLog::Source()));
197c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  net::EnsureWinsockInit();
198c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
199c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  SOCKADDR_BTH sa;
200c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ZeroMemory(&sa, sizeof(sa));
201c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  sa.addressFamily = AF_BTH;
202c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  sa.port = rfcomm_channel_;
203c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  sa.btAddr = bth_addr_;
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
205c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // TODO(rpaquay): Condider making this call non-blocking.
206c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  int status = connect(socket_fd, reinterpret_cast<SOCKADDR*>(&sa), sizeof(sa));
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DWORD error_code = WSAGetLastError();
208c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!(status == 0 || error_code == WSAEINPROGRESS)) {
209c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    LOG(ERROR) << "Failed to connect bluetooth socket "
210c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch               << "(" << device_address_ << "): "
2115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu               << logging::SystemErrorCodeToString(error_code);
212c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    error_callback.Run("Error connecting to socket: " +
2135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                       logging::SystemErrorCodeToString(error_code));
214c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    closesocket(socket_fd);
215c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
217c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
218c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Note: We don't have a meaningful |IPEndPoint|, but that is ok since the
219c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // TCPSocket implementation does not actually require one.
220c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  int net_result =
2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      scoped_socket->AdoptConnectedSocket(socket_fd, net::IPEndPoint());
222c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (net_result != net::OK) {
223c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    error_callback.Run("Error connecting to socket: " +
2246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                       net::ErrorToString(net_result));
225c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    closesocket(socket_fd);
226c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
227c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
228c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
2295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  SetTCPSocket(scoped_socket.Pass());
230c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  success_callback.Run();
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
23346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void BluetoothSocketWin::DoListen(
2345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const BluetoothUUID& uuid,
2355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    int rfcomm_channel,
2365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const base::Closure& success_callback,
23746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const ErrorCompletionCallback& error_callback) {
238010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(socket_thread()->task_runner()->RunsTasksOnCurrentThread());
23946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(!tcp_socket() && !service_reg_data_);
2405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // The valid range is 0-30. 0 means BT_PORT_ANY and 1-30 are the
2425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // valid RFCOMM port numbers of SOCKADDR_BTH.
2435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (rfcomm_channel < 0 || rfcomm_channel > 30) {
2445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    LOG(WARNING) << "Failed to start service: "
2455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 << "Invalid RFCCOMM port " << rfcomm_channel
2465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 << ", uuid=" << uuid.value();
2475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    PostErrorCompletion(error_callback, kInvalidRfcommPort);
2485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
2495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
2525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (socket_fd == INVALID_SOCKET) {
2535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    LOG(WARNING) << "Failed to start service: create socket, "
2545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 << "winsock err=" << WSAGetLastError();
2555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    PostErrorCompletion(error_callback, kFailedToCreateSocket);
2565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
2575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Note that |socket_fd| belongs to a non-TCP address family (i.e. AF_BTH),
2605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // TCPSocket methods that involve address could not be called. So bind()
2615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // is called on |socket_fd| directly.
2625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  scoped_ptr<net::TCPSocket> scoped_socket(
2635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      new net::TCPSocket(NULL, net::NetLog::Source()));
2645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  scoped_socket->AdoptListenSocket(socket_fd);
2655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  SOCKADDR_BTH sa;
2675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  struct sockaddr* sock_addr = reinterpret_cast<struct sockaddr*>(&sa);
2685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  int sock_addr_len = sizeof(sa);
2695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ZeroMemory(&sa, sock_addr_len);
2705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  sa.addressFamily = AF_BTH;
2715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  sa.port = rfcomm_channel ? rfcomm_channel : BT_PORT_ANY;
2725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (bind(socket_fd, sock_addr, sock_addr_len) < 0) {
2735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    LOG(WARNING) << "Failed to start service: create socket, "
2745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 << "winsock err=" << WSAGetLastError();
2755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    PostErrorCompletion(error_callback, kFailedToBindSocket);
2765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
2775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  const int kListenBacklog = 5;
2805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (scoped_socket->Listen(kListenBacklog) < 0) {
2815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    LOG(WARNING) << "Failed to start service: Listen"
2825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 << "winsock err=" << WSAGetLastError();
2835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    PostErrorCompletion(error_callback, kFailedToListenOnSocket);
2845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
2855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  scoped_ptr<ServiceRegData> reg_data(new ServiceRegData);
28846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  reg_data->name = base::UTF8ToUTF16(uuid.canonical_value());
2895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (getsockname(socket_fd, sock_addr, &sock_addr_len)) {
2915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    LOG(WARNING) << "Failed to start service: getsockname, "
2925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 << "winsock err=" << WSAGetLastError();
2935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    PostErrorCompletion(error_callback, kFailedToGetSockNameForSocket);
2945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
2955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  reg_data->address = sa;
2975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  reg_data->address_info.LocalAddr.iSockaddrLength = sizeof(sa);
2995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  reg_data->address_info.LocalAddr.lpSockaddr =
3005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      reinterpret_cast<struct sockaddr*>(&reg_data->address);
3015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  reg_data->address_info.iSocketType = SOCK_STREAM;
3025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  reg_data->address_info.iProtocol = BTHPROTO_RFCOMM;
3035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::string16 cannonical_uuid = L"{" + base::ASCIIToUTF16(
3055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      uuid.canonical_value()) + L"}";
3065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!SUCCEEDED(CLSIDFromString(cannonical_uuid.c_str(), &reg_data->uuid))) {
3075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    LOG(WARNING) << "Failed to start service: "
30846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 << ", invalid uuid=" << cannonical_uuid;
30946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    PostErrorCompletion(error_callback, kInvalidUUID);
3105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
3115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
3125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  reg_data->service.dwSize = sizeof(WSAQUERYSET);
3145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  reg_data->service.lpszServiceInstanceName =
3155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      const_cast<LPWSTR>(reg_data->name.c_str());
3165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  reg_data->service.lpServiceClassId = &reg_data->uuid;
3175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  reg_data->service.dwNameSpace = NS_BTH;
3185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  reg_data->service.dwNumberOfCsAddrs = 1;
3195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  reg_data->service.lpcsaBuffer = &reg_data->address_info;
3205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (WSASetService(&reg_data->service,
3225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                    RNRSERVICE_REGISTER, 0) == SOCKET_ERROR) {
3235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    LOG(WARNING) << "Failed to register profile: WSASetService"
3245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 << "winsock err=" << WSAGetLastError();
3255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    PostErrorCompletion(error_callback, kWsaSetServiceError);
3265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
3275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
3285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
329010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  SetTCPSocket(scoped_socket.Pass());
3305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  service_reg_data_ = reg_data.Pass();
3315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  PostSuccess(success_callback);
3335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
3345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
33546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void BluetoothSocketWin::DoAccept(
33646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const AcceptCompletionCallback& success_callback,
33746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const ErrorCompletionCallback& error_callback) {
338010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(socket_thread()->task_runner()->RunsTasksOnCurrentThread());
339010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  int result = tcp_socket()->Accept(
3405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      &accept_socket_,
3415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      &accept_address_,
34246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::Bind(&BluetoothSocketWin::OnAcceptOnSocketThread,
34346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 this,
34446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 success_callback,
34546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 error_callback));
34646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (result != net::OK && result != net::ERR_IO_PENDING) {
3475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    LOG(WARNING) << "Failed to accept, net err=" << result;
34846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    PostErrorCompletion(error_callback, kFailedToAccept);
34946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
3505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
3515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
35246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void BluetoothSocketWin::OnAcceptOnSocketThread(
35346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const AcceptCompletionCallback& success_callback,
35446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const ErrorCompletionCallback& error_callback,
35546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    int accept_result) {
356010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(socket_thread()->task_runner()->RunsTasksOnCurrentThread());
3575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (accept_result != net::OK) {
3585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    LOG(WARNING) << "OnAccept error, net err=" << accept_result;
35946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    PostErrorCompletion(error_callback, kFailedToAccept);
3605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
3615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
3625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
363010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  ui_task_runner()->PostTask(
3645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    FROM_HERE,
3655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    base::Bind(&BluetoothSocketWin::OnAcceptOnUI,
3665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu               this,
3675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu               base::Passed(&accept_socket_),
36846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)               accept_address_,
36946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)               success_callback,
37046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)               error_callback));
3715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
3725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BluetoothSocketWin::OnAcceptOnUI(
3745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    scoped_ptr<net::TCPSocket> accept_socket,
37546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const net::IPEndPoint& peer_address,
37646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const AcceptCompletionCallback& success_callback,
37746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const ErrorCompletionCallback& error_callback) {
378010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
3795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
38046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const std::string peer_device_address =
38146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      IPEndPointToBluetoothAddress(peer_address);
38246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const BluetoothDevice* peer_device = adapter_->GetDevice(peer_device_address);
38346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!peer_device) {
38446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    LOG(WARNING) << "OnAccept failed with unknown device, addr="
38546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 << peer_device_address;
38646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    error_callback.Run(kFailedToAccept);
38746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
38846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
38946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
3905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_refptr<BluetoothSocketWin> peer_socket =
3915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      CreateBluetoothSocket(ui_task_runner(), socket_thread());
39246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  peer_socket->SetTCPSocket(accept_socket.Pass());
39346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  success_callback.Run(peer_device, peer_socket);
3945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
3955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace device
397