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)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/ref_counted.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "device/bluetooth/bluetooth_init_win.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "device/bluetooth/bluetooth_service_record_win.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/io_buffer.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/winsock_init.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string FormatErrorMessage(DWORD error_code) {
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TCHAR error_msg[1024];
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                0,
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                error_code,
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                0,
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                error_msg,
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                1024,
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                NULL);
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::SysWideToUTF8(error_msg);
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace device {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BluetoothSocketWin::BluetoothSocketWin(SOCKET fd) : fd_(fd) {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BluetoothSocketWin::~BluetoothSocketWin() {
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  closesocket(fd_);
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_refptr<BluetoothSocket> BluetoothSocketWin::CreateBluetoothSocket(
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const BluetoothServiceRecord& service_record) {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BluetoothSocketWin* bluetooth_socket = NULL;
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (service_record.SupportsRfcomm()) {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::EnsureWinsockInit();
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SOCKADDR_BTH sa;
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ZeroMemory(&sa, sizeof(sa));
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sa.addressFamily = AF_BTH;
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sa.port = service_record.rfcomm_channel();
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const BluetoothServiceRecordWin* service_record_win =
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        static_cast<const BluetoothServiceRecordWin*>(&service_record);
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sa.btAddr = service_record_win->bth_addr();
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int status = connect(socket_fd,
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         reinterpret_cast<SOCKADDR *>(&sa),
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         sizeof(sa));
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DWORD error_code = WSAGetLastError();
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (status == 0 || error_code == WSAEINPROGRESS) {
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bluetooth_socket =
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          new BluetoothSocketWin(socket_fd);
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(ERROR) << "Failed to connect bluetooth socket "
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          << "(" << service_record.address() << "): "
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          << "(" << error_code << ")" << FormatErrorMessage(error_code);
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      closesocket(socket_fd);
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(youngki) add support for L2CAP sockets as well.
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return scoped_refptr<BluetoothSocketWin>(bluetooth_socket);
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BluetoothSocketWin::Receive(net::GrowableIOBuffer* buffer) {
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  buffer->SetCapacity(1024);
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int bytes_read;
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  do {
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (buffer->RemainingCapacity() == 0)
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      buffer->SetCapacity(buffer->capacity() * 2);
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bytes_read = recv(fd_, buffer->data(), buffer->RemainingCapacity(), 0);
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bytes_read > 0)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      buffer->set_offset(buffer->offset() + bytes_read);
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } while (bytes_read > 0);
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DWORD error_code = WSAGetLastError();
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (bytes_read < 0 && error_code != WSAEWOULDBLOCK) {
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_message_ = FormatErrorMessage(error_code);
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BluetoothSocketWin::Send(net::DrainableIOBuffer* buffer) {
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int bytes_written;
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  do {
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bytes_written = send(fd_, buffer->data(), buffer->BytesRemaining(), 0);
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (bytes_written > 0)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      buffer->DidConsume(bytes_written);
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } while (buffer->BytesRemaining() > 0 && bytes_written > 0);
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DWORD error_code = WSAGetLastError();
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (bytes_written < 0 && error_code != WSAEWOULDBLOCK) {
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_message_ = FormatErrorMessage(error_code);
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string BluetoothSocketWin::GetLastErrorMessage() const {
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return error_message_;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace device
116