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 void BluetoothSocketChromeOS::Close() { NOTIMPLEMENTED(); }
52 void BluetoothSocketChromeOS::Disconnect(const base::Closure
& callback
) {
56 void BluetoothSocketChromeOS::Receive(
58 const ReceiveCompletionCallback
& success_callback
,
59 const ReceiveErrorCompletionCallback
& error_callback
) {
63 void BluetoothSocketChromeOS::Send(
64 scoped_refptr
<net::IOBuffer
> buffer
,
66 const SendCompletionCallback
& success_callback
,
67 const ErrorCompletionCallback
& error_callback
) {
72 bool BluetoothSocketChromeOS::Receive(net::GrowableIOBuffer
*buffer
) {
73 base::ThreadRestrictions::AssertIOAllowed();
75 if (socket_type_
== L2CAP
) {
77 if (ioctl(fd_
, FIONREAD
, &count
) < 0) {
78 error_message_
= safe_strerror(errno
);
79 LOG(WARNING
) << "Unable to get waiting data size: " << error_message_
;
83 // No bytes waiting can mean either nothing to read, or the other end has
84 // been closed, and reading zero bytes always returns zero.
86 // We can't do a short read for fear of a race where data arrives between
87 // calls and we trunctate it. So use poll() to check for the POLLHUP flag.
95 // Timeout parameter set to 0 so this call will not block.
96 if (HANDLE_EINTR(poll(&pollfd
, 1, 0)) < 0) {
97 error_message_
= safe_strerror(errno
);
98 LOG(WARNING
) << "Unable to check whether socket is closed: "
103 if (pollfd
.revents
& POLLHUP
) {
104 // TODO(keybuk, youngki): Agree a common way to flag disconnected.
105 error_message_
= "Disconnected";
110 buffer
->SetCapacity(count
);
112 buffer
->SetCapacity(1024);
117 if (buffer
->RemainingCapacity() == 0)
118 buffer
->SetCapacity(buffer
->capacity() * 2);
120 HANDLE_EINTR(read(fd_
, buffer
->data(), buffer
->RemainingCapacity()));
122 buffer
->set_offset(buffer
->offset() + bytes_read
);
123 } while (socket_type_
== RFCOMM
&& bytes_read
> 0);
125 // Ignore an error if at least one read() call succeeded; it'll be returned
126 // the next read() call.
127 if (buffer
->offset() > 0)
130 if (bytes_read
< 0) {
131 if (errno
== ECONNRESET
|| errno
== ENOTCONN
) {
132 // TODO(keybuk, youngki): Agree a common way to flag disconnected.
133 error_message_
= "Disconnected";
135 } else if (errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
) {
136 error_message_
= safe_strerror(errno
);
141 if (bytes_read
== 0 && socket_type_
== RFCOMM
) {
142 // TODO(keybuk, youngki): Agree a common way to flag disconnected.
143 error_message_
= "Disconnected";
150 bool BluetoothSocketChromeOS::Send(net::DrainableIOBuffer
*buffer
) {
151 base::ThreadRestrictions::AssertIOAllowed();
153 ssize_t bytes_written
;
156 HANDLE_EINTR(write(fd_
, buffer
->data(), buffer
->BytesRemaining()));
157 if (bytes_written
> 0)
158 buffer
->DidConsume(bytes_written
);
159 } while (buffer
->BytesRemaining() > 0 && bytes_written
> 0);
161 if (bytes_written
< 0) {
162 if (errno
== EPIPE
|| errno
== ECONNRESET
|| errno
== ENOTCONN
) {
163 // TODO(keybuk, youngki): Agree a common way to flag disconnected.
164 error_message_
= "Disconnected";
166 } else if (errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
) {
167 error_message_
= safe_strerror(errno
);
175 std::string
BluetoothSocketChromeOS::GetLastErrorMessage() const {
176 return error_message_
;
181 scoped_refptr
<device::BluetoothSocket
> BluetoothSocketChromeOS::Create(
182 dbus::FileDescriptor
* fd
) {
183 DCHECK(fd
->is_valid());
185 BluetoothSocketChromeOS
* bluetooth_socket
=
186 new BluetoothSocketChromeOS(fd
->TakeValue());
187 return scoped_refptr
<BluetoothSocketChromeOS
>(bluetooth_socket
);
190 } // namespace chromeos