Add comment to SocketStreamEventRecorder about when and how callback is called.
[chromium-blink-merge.git] / device / bluetooth / bluetooth_socket_chromeos.cc
blob81395dc14ea04ab548c054a61a6c3add20f426c5
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"
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>
14 #include <string>
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"
25 namespace chromeos {
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;
39 if (optval == SOCK_DGRAM || optval == SOCK_SEQPACKET) {
40 socket_type_ = L2CAP;
41 } else {
42 socket_type_ = RFCOMM;
46 BluetoothSocketChromeOS::~BluetoothSocketChromeOS() {
47 HANDLE_EINTR(close(fd_));
50 bool BluetoothSocketChromeOS::Receive(net::GrowableIOBuffer *buffer) {
51 base::ThreadRestrictions::AssertIOAllowed();
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;
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.
66 if (count == 0) {
67 struct pollfd pollfd;
69 pollfd.fd = fd_;
70 pollfd.events = 0;
71 pollfd.revents = 0;
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;
81 if (pollfd.revents & POLLHUP) {
82 // TODO(keybuk, youngki): Agree a common way to flag disconnected.
83 error_message_ = "Disconnected";
84 return false;
88 buffer->SetCapacity(count);
89 } else {
90 buffer->SetCapacity(1024);
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);
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;
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;
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;
125 return true;
128 bool BluetoothSocketChromeOS::Send(net::DrainableIOBuffer *buffer) {
129 base::ThreadRestrictions::AssertIOAllowed();
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);
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;
150 return true;
153 std::string BluetoothSocketChromeOS::GetLastErrorMessage() const {
154 return error_message_;
157 // static
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