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.
5 #include "device/bluetooth/bluetooth_socket_chromeos.h"
10 #include <sys/ioctl.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
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"
27 BluetoothSocketChromeOS::BluetoothSocketChromeOS(int fd
)
29 // Fetch the socket type so we read from it correctly.
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
35 LOG(WARNING
) << "Unable to get socket type: " << safe_strerror(errno
);
36 optval
= SOCK_SEQPACKET
;
39 if (optval
== SOCK_DGRAM
|| optval
== SOCK_SEQPACKET
) {
42 socket_type_
= RFCOMM
;
46 BluetoothSocketChromeOS::~BluetoothSocketChromeOS() {
50 bool BluetoothSocketChromeOS::Receive(net::GrowableIOBuffer
*buffer
) {
51 base::ThreadRestrictions::AssertIOAllowed();
53 if (socket_type_
== L2CAP
) {
55 if (ioctl(fd_
, FIONREAD
, &count
) < 0) {
56 error_message_
= safe_strerror(errno
);
57 LOG(WARNING
) << "Unable to get waiting data size: " << error_message_
;
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.
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.
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: "
81 if (pollfd
.revents
& POLLHUP
) {
82 // TODO(keybuk, youngki): Agree a common way to flag disconnected.
83 error_message_
= "Disconnected";
88 buffer
->SetCapacity(count
);
90 buffer
->SetCapacity(1024);
95 if (buffer
->RemainingCapacity() == 0)
96 buffer
->SetCapacity(buffer
->capacity() * 2);
98 HANDLE_EINTR(read(fd_
, buffer
->data(), buffer
->RemainingCapacity()));
100 buffer
->set_offset(buffer
->offset() + bytes_read
);
101 } while (socket_type_
== RFCOMM
&& bytes_read
> 0);
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)
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";
113 } else if (errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
) {
114 error_message_
= safe_strerror(errno
);
119 if (bytes_read
== 0 && socket_type_
== RFCOMM
) {
120 // TODO(keybuk, youngki): Agree a common way to flag disconnected.
121 error_message_
= "Disconnected";
128 bool BluetoothSocketChromeOS::Send(net::DrainableIOBuffer
*buffer
) {
129 base::ThreadRestrictions::AssertIOAllowed();
131 ssize_t 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);
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";
144 } else if (errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
) {
145 error_message_
= safe_strerror(errno
);
153 std::string
BluetoothSocketChromeOS::GetLastErrorMessage() const {
154 return error_message_
;
158 scoped_refptr
<device::BluetoothSocket
> BluetoothSocketChromeOS::Create(
159 dbus::FileDescriptor
* fd
) {
160 DCHECK(fd
->is_valid());
162 BluetoothSocketChromeOS
* bluetooth_socket
=
163 new BluetoothSocketChromeOS(fd
->TakeValue());;
164 return scoped_refptr
<BluetoothSocketChromeOS
>(bluetooth_socket
);
167 } // namespace chromeos