libweave: Extract weave::Stream interface

Interface is implemented in buffet using ChromeOS streams.
This breaks libweave dependency on chromeos/streams/.

BUG=brillo:1257
TEST=`FEATURES=test emerge-gizmo libweave buffet`

Change-Id: I9fa73d40810f39d5608b3cbe320bc9eca0dff4ef
Reviewed-on: https://chromium-review.googlesource.com/293321
Trybot-Ready: Vitaly Buka <vitalybuka@chromium.org>
Tested-by: Vitaly Buka <vitalybuka@chromium.org>
Reviewed-by: Alex Vakulenko <avakulenko@chromium.org>
Commit-Queue: Vitaly Buka <vitalybuka@chromium.org>
diff --git a/buffet/socket_stream.cc b/buffet/socket_stream.cc
new file mode 100644
index 0000000..4b4bbbe
--- /dev/null
+++ b/buffet/socket_stream.cc
@@ -0,0 +1,122 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <arpa/inet.h>
+#include <map>
+#include <netdb.h>
+#include <string>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <base/bind.h>
+#include <base/files/file_util.h>
+#include <chromeos/streams/file_stream.h>
+#include <chromeos/streams/tls_stream.h>
+
+#include "buffet/socket_stream.h"
+
+namespace buffet {
+
+namespace {
+
+int ConnectSocket(const std::string& host, uint16_t port) {
+  std::string service = std::to_string(port);
+  addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM};
+  addrinfo* result = nullptr;
+  if (getaddrinfo(host.c_str(), service.c_str(), &hints, &result)) {
+    PLOG(WARNING) << "Failed to resolve host name: " << host;
+    return -1;
+  }
+
+  int socket_fd = -1;
+  for (const addrinfo* info = result; info != nullptr; info = info->ai_next) {
+    socket_fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
+    if (socket_fd < 0)
+      continue;
+
+    char str[INET6_ADDRSTRLEN] = {};
+    inet_ntop(info->ai_family, info->ai_addr, str, info->ai_addrlen);
+    LOG(INFO) << "Connecting to address: " << str;
+    if (connect(socket_fd, info->ai_addr, info->ai_addrlen) == 0)
+      break;  // Success.
+
+    PLOG(WARNING) << "Failed to connect to address: " << str;
+    close(socket_fd);
+    socket_fd = -1;
+  }
+
+  freeaddrinfo(result);
+  return socket_fd;
+}
+
+void OnSuccess(const base::Callback<void(std::unique_ptr<weave::Stream>)>&
+                   success_callback,
+               chromeos::StreamPtr tls_stream) {
+  success_callback.Run(
+      std::unique_ptr<weave::Stream>{new SocketStream{std::move(tls_stream)}});
+}
+
+}  // namespace
+
+bool SocketStream::ReadAsync(
+    void* buffer,
+    size_t size_to_read,
+    const base::Callback<void(size_t)>& success_callback,
+    const base::Callback<void(const chromeos::Error*)>& error_callback,
+    chromeos::ErrorPtr* error) {
+  return ptr_->ReadAsync(buffer, size_to_read, success_callback, error_callback,
+                         error);
+}
+
+bool SocketStream::WriteAllAsync(
+    const void* buffer,
+    size_t size_to_write,
+    const base::Closure& success_callback,
+    const base::Callback<void(const chromeos::Error*)>& error_callback,
+    chromeos::ErrorPtr* error) {
+  return ptr_->WriteAllAsync(buffer, size_to_write, success_callback,
+                             error_callback, error);
+}
+
+bool SocketStream::FlushBlocking(chromeos::ErrorPtr* error) {
+  return ptr_->FlushBlocking(error);
+}
+
+bool SocketStream::CloseBlocking(chromeos::ErrorPtr* error) {
+  return ptr_->CloseBlocking(error);
+}
+
+void SocketStream::CancelPendingAsyncOperations() {
+  return ptr_->CancelPendingAsyncOperations();
+}
+
+std::unique_ptr<weave::Stream> SocketStream::ConnectBlocking(
+    const std::string& host,
+    uint16_t port) {
+  int socket_fd = ConnectSocket(host, port);
+  if (socket_fd <= 0)
+    return nullptr;
+
+  auto ptr_ =
+      chromeos::FileStream::FromFileDescriptor(socket_fd, true, nullptr);
+  if (ptr_)
+    return std::unique_ptr<Stream>{new SocketStream{std::move(ptr_)}};
+
+  close(socket_fd);
+  return nullptr;
+}
+
+void SocketStream::TlsConnect(
+    std::unique_ptr<Stream> socket,
+    const std::string& host,
+    const base::Callback<void(std::unique_ptr<Stream>)>& success_callback,
+    const base::Callback<void(const chromeos::Error*)>& error_callback) {
+  SocketStream* stream = static_cast<SocketStream*>(socket.get());
+  chromeos::TlsStream::Connect(std::move(stream->ptr_), host,
+                               base::Bind(&OnSuccess, success_callback),
+                               error_callback);
+}
+
+}  // namespace buffet