Home | History | Annotate | Download | only in bluetooth
      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.
      4 
      5 #include "device/bluetooth/bluetooth_socket_win.h"
      6 
      7 #include <objbase.h>
      8 
      9 #include <string>
     10 
     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"
     26 
     27 namespace {
     28 
     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.";
     39 
     40 std::string IPEndPointToBluetoothAddress(const net::IPEndPoint& end_point) {
     41   if (end_point.address().size() != net::kBluetoothAddressSize)
     42     return std::string();
     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]);
     53 }
     54 
     55 }  // namespace
     56 
     57 namespace device {
     58 
     59 struct BluetoothSocketWin::ServiceRegData {
     60   ServiceRegData() {
     61     ZeroMemory(&address, sizeof(address));
     62     ZeroMemory(&address_info, sizeof(address_info));
     63     ZeroMemory(&uuid, sizeof(uuid));
     64     ZeroMemory(&service, sizeof(service));
     65   }
     66 
     67   SOCKADDR_BTH address;
     68   CSADDR_INFO address_info;
     69   GUID uuid;
     70   base::string16 name;
     71   WSAQUERYSET service;
     72 };
     73 
     74 // static
     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());
     80 
     81   return make_scoped_refptr(
     82       new BluetoothSocketWin(ui_task_runner, socket_thread));
     83 }
     84 
     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) {
     92 }
     93 
     94 BluetoothSocketWin::~BluetoothSocketWin() {
     95 }
     96 
     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());
    103   DCHECK(device);
    104 
    105   if (!uuid.IsValid()) {
    106     error_callback.Run(kInvalidUUID);
    107     return;
    108   }
    109 
    110   const BluetoothServiceRecordWin* service_record_win =
    111       device->GetServiceRecord(uuid);
    112   if (!service_record_win) {
    113     error_callback.Run(kInvalidUUID);
    114     return;
    115   }
    116 
    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();
    122   }
    123 
    124   socket_thread()->task_runner()->PostTask(
    125       FROM_HERE,
    126       base::Bind(
    127           &BluetoothSocketWin::DoConnect,
    128           this,
    129           base::Bind(&BluetoothSocketWin::PostSuccess, this, success_callback),
    130           base::Bind(
    131               &BluetoothSocketWin::PostErrorCompletion, this, error_callback)));
    132 }
    133 
    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());
    140 
    141   adapter_ = adapter;
    142   int rfcomm_channel = options.channel ? *options.channel : 0;
    143 
    144   // TODO(xiyuan): Use |options.name|.
    145   socket_thread()->task_runner()->PostTask(
    146       FROM_HERE,
    147       base::Bind(&BluetoothSocketWin::DoListen,
    148                  this,
    149                  uuid,
    150                  rfcomm_channel,
    151                  success_callback,
    152                  error_callback));
    153 }
    154 
    155 void BluetoothSocketWin::ResetData() {
    156   if (service_reg_data_) {
    157     if (WSASetService(&service_reg_data_->service,RNRSERVICE_DELETE, 0) ==
    158         SOCKET_ERROR) {
    159       LOG(WARNING) << "Failed to unregister service.";
    160     }
    161     service_reg_data_.reset();
    162   }
    163 }
    164 
    165 void BluetoothSocketWin::Accept(
    166     const AcceptCompletionCallback& success_callback,
    167     const ErrorCompletionCallback& error_callback) {
    168   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    169 
    170   socket_thread()->task_runner()->PostTask(
    171       FROM_HERE,
    172       base::Bind(&BluetoothSocketWin::DoAccept,
    173                  this,
    174                  success_callback,
    175                  error_callback));
    176 }
    177 
    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();
    183 
    184   if (tcp_socket()) {
    185     error_callback.Run(kSocketAlreadyConnected);
    186     return;
    187   }
    188 
    189   if (!supports_rfcomm_) {
    190     // TODO(youngki) add support for L2CAP sockets as well.
    191     error_callback.Run(kL2CAPNotSupported);
    192     return;
    193   }
    194 
    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);
    199   SOCKADDR_BTH sa;
    200   ZeroMemory(&sa, sizeof(sa));
    201   sa.addressFamily = AF_BTH;
    202   sa.port = rfcomm_channel_;
    203   sa.btAddr = bth_addr_;
    204 
    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);
    215     return;
    216   }
    217 
    218   // Note: We don't have a meaningful |IPEndPoint|, but that is ok since the
    219   // TCPSocket implementation does not actually require one.
    220   int net_result =
    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);
    226     return;
    227   }
    228 
    229   SetTCPSocket(scoped_socket.Pass());
    230   success_callback.Run();
    231 }
    232 
    233 void BluetoothSocketWin::DoListen(
    234     const BluetoothUUID& uuid,
    235     int rfcomm_channel,
    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_);
    240 
    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);
    248     return;
    249   }
    250 
    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);
    256     return;
    257   }
    258 
    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);
    265 
    266   SOCKADDR_BTH sa;
    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);
    276     return;
    277   }
    278 
    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);
    284     return;
    285   }
    286 
    287   scoped_ptr<ServiceRegData> reg_data(new ServiceRegData);
    288   reg_data->name = base::UTF8ToUTF16(uuid.canonical_value());
    289 
    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);
    294     return;
    295   }
    296   reg_data->address = sa;
    297 
    298   reg_data->address_info.LocalAddr.iSockaddrLength = sizeof(sa);
    299   reg_data->address_info.LocalAddr.lpSockaddr =
    300       reinterpret_cast<struct sockaddr*>(&reg_data->address);
    301   reg_data->address_info.iSocketType = SOCK_STREAM;
    302   reg_data->address_info.iProtocol = BTHPROTO_RFCOMM;
    303 
    304   base::string16 cannonical_uuid = L"{" + base::ASCIIToUTF16(
    305       uuid.canonical_value()) + L"}";
    306   if (!SUCCEEDED(CLSIDFromString(cannonical_uuid.c_str(), &reg_data->uuid))) {
    307     LOG(WARNING) << "Failed to start service: "
    308                  << ", invalid uuid=" << cannonical_uuid;
    309     PostErrorCompletion(error_callback, kInvalidUUID);
    310     return;
    311   }
    312 
    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 = &reg_data->uuid;
    317   reg_data->service.dwNameSpace = NS_BTH;
    318   reg_data->service.dwNumberOfCsAddrs = 1;
    319   reg_data->service.lpcsaBuffer = &reg_data->address_info;
    320 
    321   if (WSASetService(&reg_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);
    326     return;
    327   }
    328 
    329   SetTCPSocket(scoped_socket.Pass());
    330   service_reg_data_ = reg_data.Pass();
    331 
    332   PostSuccess(success_callback);
    333 }
    334 
    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(
    340       &accept_socket_,
    341       &accept_address_,
    342       base::Bind(&BluetoothSocketWin::OnAcceptOnSocketThread,
    343                  this,
    344                  success_callback,
    345                  error_callback));
    346   if (result != net::OK && result != net::ERR_IO_PENDING) {
    347     LOG(WARNING) << "Failed to accept, net err=" << result;
    348     PostErrorCompletion(error_callback, kFailedToAccept);
    349   }
    350 }
    351 
    352 void BluetoothSocketWin::OnAcceptOnSocketThread(
    353     const AcceptCompletionCallback& success_callback,
    354     const ErrorCompletionCallback& error_callback,
    355     int accept_result) {
    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);
    360     return;
    361   }
    362 
    363   ui_task_runner()->PostTask(
    364     FROM_HERE,
    365     base::Bind(&BluetoothSocketWin::OnAcceptOnUI,
    366                this,
    367                base::Passed(&accept_socket_),
    368                accept_address_,
    369                success_callback,
    370                error_callback));
    371 }
    372 
    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());
    379 
    380   const std::string peer_device_address =
    381       IPEndPointToBluetoothAddress(peer_address);
    382   const BluetoothDevice* peer_device = adapter_->GetDevice(peer_device_address);
    383   if (!peer_device) {
    384     LOG(WARNING) << "OnAccept failed with unknown device, addr="
    385                  << peer_device_address;
    386     error_callback.Run(kFailedToAccept);
    387     return;
    388   }
    389 
    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);
    394 }
    395 
    396 }  // namespace device
    397