Home | History | Annotate | Download | only in bluetooth
      1 // Copyright 2013 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_chromeos.h"
      6 
      7 #include <errno.h>
      8 #include <poll.h>
      9 #include <unistd.h>
     10 #include <sys/ioctl.h>
     11 #include <sys/types.h>
     12 #include <sys/socket.h>
     13 
     14 #include <string>
     15 
     16 #include "base/logging.h"
     17 #include "base/memory/ref_counted.h"
     18 #include "base/posix/eintr_wrapper.h"
     19 #include "base/safe_strerror_posix.h"
     20 #include "base/threading/thread_restrictions.h"
     21 #include "dbus/file_descriptor.h"
     22 #include "device/bluetooth/bluetooth_socket.h"
     23 #include "net/base/io_buffer.h"
     24 
     25 namespace chromeos {
     26 
     27 BluetoothSocketChromeOS::BluetoothSocketChromeOS(int fd)
     28     : fd_(fd) {
     29   // Fetch the socket type so we read from it correctly.
     30   int optval;
     31   socklen_t opt_len = sizeof optval;
     32   if (getsockopt(fd_, SOL_SOCKET, SO_TYPE, &optval, &opt_len) < 0) {
     33     // Sequenced packet is the safest assumption since it won't result in
     34     // truncated packets.
     35     LOG(WARNING) << "Unable to get socket type: " << safe_strerror(errno);
     36     optval = SOCK_SEQPACKET;
     37   }
     38 
     39   if (optval == SOCK_DGRAM || optval == SOCK_SEQPACKET) {
     40     socket_type_ = L2CAP;
     41   } else {
     42     socket_type_ = RFCOMM;
     43   }
     44 }
     45 
     46 BluetoothSocketChromeOS::~BluetoothSocketChromeOS() {
     47   close(fd_);
     48 }
     49 
     50 bool BluetoothSocketChromeOS::Receive(net::GrowableIOBuffer *buffer) {
     51   base::ThreadRestrictions::AssertIOAllowed();
     52 
     53   if (socket_type_ == L2CAP) {
     54     int count;
     55     if (ioctl(fd_, FIONREAD, &count) < 0) {
     56       error_message_ = safe_strerror(errno);
     57       LOG(WARNING) << "Unable to get waiting data size: " << error_message_;
     58       return true;
     59     }
     60 
     61     // No bytes waiting can mean either nothing to read, or the other end has
     62     // been closed, and reading zero bytes always returns zero.
     63     //
     64     // We can't do a short read for fear of a race where data arrives between
     65     // calls and we trunctate it. So use poll() to check for the POLLHUP flag.
     66     if (count == 0) {
     67       struct pollfd pollfd;
     68 
     69       pollfd.fd = fd_;
     70       pollfd.events = 0;
     71       pollfd.revents = 0;
     72 
     73       // Timeout parameter set to 0 so this call will not block.
     74       if (HANDLE_EINTR(poll(&pollfd, 1, 0)) < 0) {
     75         error_message_ = safe_strerror(errno);
     76         LOG(WARNING) << "Unable to check whether socket is closed: "
     77                      << error_message_;
     78         return false;
     79       }
     80 
     81       if (pollfd.revents & POLLHUP) {
     82         // TODO(keybuk, youngki): Agree a common way to flag disconnected.
     83         error_message_ = "Disconnected";
     84         return false;
     85       }
     86     }
     87 
     88     buffer->SetCapacity(count);
     89   } else {
     90     buffer->SetCapacity(1024);
     91   }
     92 
     93   ssize_t bytes_read;
     94   do {
     95     if (buffer->RemainingCapacity() == 0)
     96       buffer->SetCapacity(buffer->capacity() * 2);
     97     bytes_read =
     98         HANDLE_EINTR(read(fd_, buffer->data(), buffer->RemainingCapacity()));
     99     if (bytes_read > 0)
    100       buffer->set_offset(buffer->offset() + bytes_read);
    101   } while (socket_type_ == RFCOMM && bytes_read > 0);
    102 
    103   // Ignore an error if at least one read() call succeeded; it'll be returned
    104   // the next read() call.
    105   if (buffer->offset() > 0)
    106     return true;
    107 
    108   if (bytes_read < 0) {
    109     if (errno == ECONNRESET || errno == ENOTCONN) {
    110       // TODO(keybuk, youngki): Agree a common way to flag disconnected.
    111       error_message_ = "Disconnected";
    112       return false;
    113     } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
    114       error_message_ = safe_strerror(errno);
    115       return false;
    116     }
    117   }
    118 
    119   if (bytes_read == 0 && socket_type_ == RFCOMM) {
    120     // TODO(keybuk, youngki): Agree a common way to flag disconnected.
    121     error_message_ = "Disconnected";
    122     return false;
    123   }
    124 
    125   return true;
    126 }
    127 
    128 bool BluetoothSocketChromeOS::Send(net::DrainableIOBuffer *buffer) {
    129   base::ThreadRestrictions::AssertIOAllowed();
    130 
    131   ssize_t bytes_written;
    132   do {
    133     bytes_written =
    134         HANDLE_EINTR(write(fd_, buffer->data(), buffer->BytesRemaining()));
    135     if (bytes_written > 0)
    136       buffer->DidConsume(bytes_written);
    137   } while (buffer->BytesRemaining() > 0 && bytes_written > 0);
    138 
    139   if (bytes_written < 0) {
    140     if (errno == EPIPE || errno == ECONNRESET || errno == ENOTCONN) {
    141       // TODO(keybuk, youngki): Agree a common way to flag disconnected.
    142       error_message_ = "Disconnected";
    143       return false;
    144     } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
    145       error_message_ = safe_strerror(errno);
    146       return false;
    147     }
    148   }
    149 
    150   return true;
    151 }
    152 
    153 std::string BluetoothSocketChromeOS::GetLastErrorMessage() const {
    154   return error_message_;
    155 }
    156 
    157 // static
    158 scoped_refptr<device::BluetoothSocket> BluetoothSocketChromeOS::Create(
    159     dbus::FileDescriptor* fd) {
    160   DCHECK(fd->is_valid());
    161 
    162   BluetoothSocketChromeOS* bluetooth_socket =
    163       new BluetoothSocketChromeOS(fd->TakeValue());;
    164   return scoped_refptr<BluetoothSocketChromeOS>(bluetooth_socket);
    165 }
    166 
    167 }  // namespace chromeos
    168