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 <string>
      8 
      9 #include "base/logging.h"
     10 #include "base/memory/ref_counted.h"
     11 #include "base/strings/sys_string_conversions.h"
     12 #include "device/bluetooth/bluetooth_init_win.h"
     13 #include "device/bluetooth/bluetooth_service_record_win.h"
     14 #include "net/base/io_buffer.h"
     15 #include "net/base/winsock_init.h"
     16 
     17 namespace {
     18 
     19 std::string FormatErrorMessage(DWORD error_code) {
     20   TCHAR error_msg[1024];
     21   FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
     22                 0,
     23                 error_code,
     24                 0,
     25                 error_msg,
     26                 1024,
     27                 NULL);
     28   return base::SysWideToUTF8(error_msg);
     29 }
     30 
     31 }  // namespace
     32 
     33 namespace device {
     34 
     35 BluetoothSocketWin::BluetoothSocketWin(SOCKET fd) : fd_(fd) {
     36 }
     37 
     38 BluetoothSocketWin::~BluetoothSocketWin() {
     39   closesocket(fd_);
     40 }
     41 
     42 // static
     43 scoped_refptr<BluetoothSocket> BluetoothSocketWin::CreateBluetoothSocket(
     44     const BluetoothServiceRecord& service_record) {
     45   BluetoothSocketWin* bluetooth_socket = NULL;
     46   if (service_record.SupportsRfcomm()) {
     47     net::EnsureWinsockInit();
     48     SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
     49     SOCKADDR_BTH sa;
     50     ZeroMemory(&sa, sizeof(sa));
     51     sa.addressFamily = AF_BTH;
     52     sa.port = service_record.rfcomm_channel();
     53     const BluetoothServiceRecordWin* service_record_win =
     54         static_cast<const BluetoothServiceRecordWin*>(&service_record);
     55     sa.btAddr = service_record_win->bth_addr();
     56 
     57     int status = connect(socket_fd,
     58                          reinterpret_cast<SOCKADDR *>(&sa),
     59                          sizeof(sa));
     60     DWORD error_code = WSAGetLastError();
     61     if (status == 0 || error_code == WSAEINPROGRESS) {
     62       bluetooth_socket =
     63           new BluetoothSocketWin(socket_fd);
     64     } else {
     65       LOG(ERROR) << "Failed to connect bluetooth socket "
     66           << "(" << service_record.address() << "): "
     67           << "(" << error_code << ")" << FormatErrorMessage(error_code);
     68       closesocket(socket_fd);
     69     }
     70   }
     71   // TODO(youngki) add support for L2CAP sockets as well.
     72 
     73   return scoped_refptr<BluetoothSocketWin>(bluetooth_socket);
     74 }
     75 
     76 bool BluetoothSocketWin::Receive(net::GrowableIOBuffer* buffer) {
     77   buffer->SetCapacity(1024);
     78   int bytes_read;
     79   do {
     80     if (buffer->RemainingCapacity() == 0)
     81       buffer->SetCapacity(buffer->capacity() * 2);
     82     bytes_read = recv(fd_, buffer->data(), buffer->RemainingCapacity(), 0);
     83     if (bytes_read > 0)
     84       buffer->set_offset(buffer->offset() + bytes_read);
     85   } while (bytes_read > 0);
     86 
     87   DWORD error_code = WSAGetLastError();
     88   if (bytes_read < 0 && error_code != WSAEWOULDBLOCK) {
     89     error_message_ = FormatErrorMessage(error_code);
     90     return false;
     91   }
     92   return true;
     93 }
     94 
     95 bool BluetoothSocketWin::Send(net::DrainableIOBuffer* buffer) {
     96   int bytes_written;
     97   do {
     98     bytes_written = send(fd_, buffer->data(), buffer->BytesRemaining(), 0);
     99     if (bytes_written > 0)
    100       buffer->DidConsume(bytes_written);
    101   } while (buffer->BytesRemaining() > 0 && bytes_written > 0);
    102 
    103   DWORD error_code = WSAGetLastError();
    104   if (bytes_written < 0 && error_code != WSAEWOULDBLOCK) {
    105     error_message_ = FormatErrorMessage(error_code);
    106     return false;
    107   }
    108   return true;
    109 }
    110 
    111 std::string BluetoothSocketWin::GetLastErrorMessage() const {
    112   return error_message_;
    113 }
    114 
    115 }  // namespace device
    116