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 17namespace { 18 19std::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 33namespace device { 34 35BluetoothSocketWin::BluetoothSocketWin(SOCKET fd) : fd_(fd) { 36} 37 38BluetoothSocketWin::~BluetoothSocketWin() { 39 closesocket(fd_); 40} 41 42// static 43scoped_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 76bool 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 95bool 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 111std::string BluetoothSocketWin::GetLastErrorMessage() const { 112 return error_message_; 113} 114 115} // namespace device 116