Revert 264226 "Reduce dependency of TiclInvalidationService on P..."
[chromium-blink-merge.git] / device / bluetooth / bluetooth_socket_chromeos.cc
blob7725b6d9a60aca544cdfef2508e3500047b97d53
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 close(fd_);
50 void BluetoothSocketChromeOS::Close() { NOTIMPLEMENTED(); }
52 void BluetoothSocketChromeOS::Disconnect(const base::Closure& callback) {
53 NOTIMPLEMENTED();
56 void BluetoothSocketChromeOS::Receive(
57 int count,
58 const ReceiveCompletionCallback& success_callback,
59 const ReceiveErrorCompletionCallback& error_callback) {
60 NOTIMPLEMENTED();
63 void BluetoothSocketChromeOS::Send(
64 scoped_refptr<net::IOBuffer> buffer,
65 int buffer_size,
66 const SendCompletionCallback& success_callback,
67 const ErrorCompletionCallback& error_callback) {
68 NOTIMPLEMENTED();
71 #if 0
72 bool BluetoothSocketChromeOS::Receive(net::GrowableIOBuffer *buffer) {
73 base::ThreadRestrictions::AssertIOAllowed();
75 if (socket_type_ == L2CAP) {
76 int count;
77 if (ioctl(fd_, FIONREAD, &count) < 0) {
78 error_message_ = safe_strerror(errno);
79 LOG(WARNING) << "Unable to get waiting data size: " << error_message_;
80 return true;
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.
88 if (count == 0) {
89 struct pollfd pollfd;
91 pollfd.fd = fd_;
92 pollfd.events = 0;
93 pollfd.revents = 0;
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: "
99 << error_message_;
100 return false;
103 if (pollfd.revents & POLLHUP) {
104 // TODO(keybuk, youngki): Agree a common way to flag disconnected.
105 error_message_ = "Disconnected";
106 return false;
110 buffer->SetCapacity(count);
111 } else {
112 buffer->SetCapacity(1024);
115 ssize_t bytes_read;
116 do {
117 if (buffer->RemainingCapacity() == 0)
118 buffer->SetCapacity(buffer->capacity() * 2);
119 bytes_read =
120 HANDLE_EINTR(read(fd_, buffer->data(), buffer->RemainingCapacity()));
121 if (bytes_read > 0)
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)
128 return true;
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";
134 return false;
135 } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
136 error_message_ = safe_strerror(errno);
137 return false;
141 if (bytes_read == 0 && socket_type_ == RFCOMM) {
142 // TODO(keybuk, youngki): Agree a common way to flag disconnected.
143 error_message_ = "Disconnected";
144 return false;
147 return true;
150 bool BluetoothSocketChromeOS::Send(net::DrainableIOBuffer *buffer) {
151 base::ThreadRestrictions::AssertIOAllowed();
153 ssize_t bytes_written;
154 do {
155 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";
165 return false;
166 } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
167 error_message_ = safe_strerror(errno);
168 return false;
172 return true;
175 std::string BluetoothSocketChromeOS::GetLastErrorMessage() const {
176 return error_message_;
178 #endif
180 // static
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