Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / device / bluetooth / bluetooth_socket_chromeos.cc
index 85544d2..86cdc48 100644 (file)
 
 #include "device/bluetooth/bluetooth_socket_chromeos.h"
 
-#include <errno.h>
-#include <poll.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
 #include <string>
 
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/safe_strerror_posix.h"
+#include "base/sequenced_task_runner.h"
 #include "base/threading/thread_restrictions.h"
 #include "dbus/file_descriptor.h"
 #include "device/bluetooth/bluetooth_socket.h"
-#include "net/base/io_buffer.h"
+#include "device/bluetooth/bluetooth_socket_net.h"
+#include "device/bluetooth/bluetooth_socket_thread.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+
+namespace {
+
+const char kSocketAlreadyConnected[] = "Socket is already connected.";
+
+}  // namespace
 
 namespace chromeos {
 
-BluetoothSocketChromeOS::BluetoothSocketChromeOS(int fd)
-    : fd_(fd) {
-  // Fetch the socket type so we read from it correctly.
-  int optval;
-  socklen_t opt_len = sizeof optval;
-  if (getsockopt(fd_, SOL_SOCKET, SO_TYPE, &optval, &opt_len) < 0) {
-    // Sequenced packet is the safest assumption since it won't result in
-    // truncated packets.
-    LOG(WARNING) << "Unable to get socket type: " << safe_strerror(errno);
-    optval = SOCK_SEQPACKET;
-  }
+// static
+scoped_refptr<BluetoothSocketChromeOS>
+BluetoothSocketChromeOS::CreateBluetoothSocket(
+    scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
+    scoped_refptr<device::BluetoothSocketThread> socket_thread,
+    net::NetLog* net_log,
+    const net::NetLog::Source& source) {
+  DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
+
+  return make_scoped_refptr(
+      new BluetoothSocketChromeOS(
+          ui_task_runner, socket_thread, net_log, source));
+}
 
-  if (optval == SOCK_DGRAM || optval == SOCK_SEQPACKET) {
-    socket_type_ = L2CAP;
-  } else {
-    socket_type_ = RFCOMM;
-  }
+BluetoothSocketChromeOS::BluetoothSocketChromeOS(
+    scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
+    scoped_refptr<device::BluetoothSocketThread> socket_thread,
+    net::NetLog* net_log,
+    const net::NetLog::Source& source)
+    : BluetoothSocketNet(ui_task_runner, socket_thread, net_log, source) {
 }
 
 BluetoothSocketChromeOS::~BluetoothSocketChromeOS() {
-  close(fd_);
 }
 
-bool BluetoothSocketChromeOS::Receive(net::GrowableIOBuffer *buffer) {
-  base::ThreadRestrictions::AssertIOAllowed();
-
-  if (socket_type_ == L2CAP) {
-    int count;
-    if (ioctl(fd_, FIONREAD, &count) < 0) {
-      error_message_ = safe_strerror(errno);
-      LOG(WARNING) << "Unable to get waiting data size: " << error_message_;
-      return true;
-    }
-
-    // No bytes waiting can mean either nothing to read, or the other end has
-    // been closed, and reading zero bytes always returns zero.
-    //
-    // We can't do a short read for fear of a race where data arrives between
-    // calls and we trunctate it. So use poll() to check for the POLLHUP flag.
-    if (count == 0) {
-      struct pollfd pollfd;
-
-      pollfd.fd = fd_;
-      pollfd.events = 0;
-      pollfd.revents = 0;
-
-      // Timeout parameter set to 0 so this call will not block.
-      if (HANDLE_EINTR(poll(&pollfd, 1, 0)) < 0) {
-        error_message_ = safe_strerror(errno);
-        LOG(WARNING) << "Unable to check whether socket is closed: "
-                     << error_message_;
-        return false;
-      }
-
-      if (pollfd.revents & POLLHUP) {
-        // TODO(keybuk, youngki): Agree a common way to flag disconnected.
-        error_message_ = "Disconnected";
-        return false;
-      }
-    }
-
-    buffer->SetCapacity(count);
-  } else {
-    buffer->SetCapacity(1024);
-  }
-
-  ssize_t bytes_read;
-  do {
-    if (buffer->RemainingCapacity() == 0)
-      buffer->SetCapacity(buffer->capacity() * 2);
-    bytes_read =
-        HANDLE_EINTR(read(fd_, buffer->data(), buffer->RemainingCapacity()));
-    if (bytes_read > 0)
-      buffer->set_offset(buffer->offset() + bytes_read);
-  } while (socket_type_ == RFCOMM && bytes_read > 0);
-
-  // Ignore an error if at least one read() call succeeded; it'll be returned
-  // the next read() call.
-  if (buffer->offset() > 0)
-    return true;
-
-  if (bytes_read < 0) {
-    if (errno == ECONNRESET || errno == ENOTCONN) {
-      // TODO(keybuk, youngki): Agree a common way to flag disconnected.
-      error_message_ = "Disconnected";
-      return false;
-    } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
-      error_message_ = safe_strerror(errno);
-      return false;
-    }
-  }
-
-  if (bytes_read == 0 && socket_type_ == RFCOMM) {
-    // TODO(keybuk, youngki): Agree a common way to flag disconnected.
-    error_message_ = "Disconnected";
-    return false;
-  }
-
-  return true;
+void BluetoothSocketChromeOS::Connect(
+    scoped_ptr<dbus::FileDescriptor> fd,
+    const base::Closure& success_callback,
+    const ErrorCompletionCallback& error_callback) {
+  DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
+
+  socket_thread()->task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(
+          &BluetoothSocketChromeOS::DoConnect,
+          this,
+          base::Passed(&fd),
+          base::Bind(&BluetoothSocketChromeOS::PostSuccess,
+                     this,
+                     success_callback),
+          base::Bind(&BluetoothSocketChromeOS::PostErrorCompletion,
+                     this,
+                     error_callback)));
 }
 
-bool BluetoothSocketChromeOS::Send(net::DrainableIOBuffer *buffer) {
+void BluetoothSocketChromeOS::DoConnect(
+    scoped_ptr<dbus::FileDescriptor> fd,
+    const base::Closure& success_callback,
+    const ErrorCompletionCallback& error_callback) {
+  DCHECK(socket_thread()->task_runner()->RunsTasksOnCurrentThread());
   base::ThreadRestrictions::AssertIOAllowed();
+  DCHECK(fd->is_valid());
 
-  ssize_t bytes_written;
-  do {
-    bytes_written =
-        HANDLE_EINTR(write(fd_, buffer->data(), buffer->BytesRemaining()));
-    if (bytes_written > 0)
-      buffer->DidConsume(bytes_written);
-  } while (buffer->BytesRemaining() > 0 && bytes_written > 0);
-
-  if (bytes_written < 0) {
-    if (errno == EPIPE || errno == ECONNRESET || errno == ENOTCONN) {
-      // TODO(keybuk, youngki): Agree a common way to flag disconnected.
-      error_message_ = "Disconnected";
-      return false;
-    } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
-      error_message_ = safe_strerror(errno);
-      return false;
-    }
+  if (tcp_socket()) {
+    error_callback.Run(kSocketAlreadyConnected);
+    return;
   }
 
-  return true;
-}
+  ResetTCPSocket();
 
-std::string BluetoothSocketChromeOS::GetLastErrorMessage() const {
-  return error_message_;
-}
-
-// static
-scoped_refptr<device::BluetoothSocket> BluetoothSocketChromeOS::Create(
-    dbus::FileDescriptor* fd) {
-  DCHECK(fd->is_valid());
+  // Note: We don't have a meaningful |IPEndPoint|, but that is ok since the
+  // TCPSocket implementation does not actually require one.
+  int net_result = tcp_socket()->AdoptConnectedSocket(fd->value(),
+                                                      net::IPEndPoint());
+  if (net_result != net::OK) {
+    error_callback.Run("Error connecting to socket: " +
+                       std::string(net::ErrorToString(net_result)));
+    return;
+  }
 
-  BluetoothSocketChromeOS* bluetooth_socket =
-      new BluetoothSocketChromeOS(fd->TakeValue());
-  return scoped_refptr<BluetoothSocketChromeOS>(bluetooth_socket);
+  fd->TakeValue();
+  success_callback.Run();
 }
 
 }  // namespace chromeos