socket_stream.cc revision 35d119ab40cdfd317c46abe08472e2981adf90b5
1// Copyright 2015 The Chromium OS 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.
4
5#include <arpa/inet.h>
6#include <map>
7#include <netdb.h>
8#include <string>
9#include <sys/socket.h>
10#include <sys/types.h>
11#include <unistd.h>
12
13#include <base/bind.h>
14#include <base/files/file_util.h>
15#include <chromeos/streams/file_stream.h>
16#include <chromeos/streams/tls_stream.h>
17
18#include "buffet/socket_stream.h"
19#include "buffet/weave_error_conversion.h"
20
21namespace buffet {
22
23namespace {
24
25int ConnectSocket(const std::string& host, uint16_t port) {
26  std::string service = std::to_string(port);
27  addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM};
28  addrinfo* result = nullptr;
29  if (getaddrinfo(host.c_str(), service.c_str(), &hints, &result)) {
30    PLOG(WARNING) << "Failed to resolve host name: " << host;
31    return -1;
32  }
33
34  int socket_fd = -1;
35  for (const addrinfo* info = result; info != nullptr; info = info->ai_next) {
36    socket_fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
37    if (socket_fd < 0)
38      continue;
39
40    char str[INET6_ADDRSTRLEN] = {};
41    inet_ntop(info->ai_family, info->ai_addr, str, info->ai_addrlen);
42    LOG(INFO) << "Connecting to address: " << str;
43    if (connect(socket_fd, info->ai_addr, info->ai_addrlen) == 0)
44      break;  // Success.
45
46    PLOG(WARNING) << "Failed to connect to address: " << str;
47    close(socket_fd);
48    socket_fd = -1;
49  }
50
51  freeaddrinfo(result);
52  return socket_fd;
53}
54
55void OnSuccess(const base::Callback<void(std::unique_ptr<weave::Stream>)>&
56                   success_callback,
57               chromeos::StreamPtr tls_stream) {
58  success_callback.Run(
59      std::unique_ptr<weave::Stream>{new SocketStream{std::move(tls_stream)}});
60}
61
62void OnError(const base::Callback<void(const weave::Error*)>& error_callback,
63             const chromeos::Error* chromeos_error) {
64  weave::ErrorPtr error;
65  ConvertError(*chromeos_error, &error);
66  error_callback.Run(error.get());
67}
68
69}  // namespace
70
71bool SocketStream::ReadAsync(
72    void* buffer,
73    size_t size_to_read,
74    const base::Callback<void(size_t)>& success_callback,
75    const base::Callback<void(const weave::Error*)>& error_callback,
76    weave::ErrorPtr* error) {
77  chromeos::ErrorPtr chromeos_error;
78  if (!ptr_->ReadAsync(buffer, size_to_read, success_callback,
79                       base::Bind(&OnError, error_callback), &chromeos_error)) {
80    ConvertError(*chromeos_error, error);
81    return false;
82  }
83  return true;
84}
85
86bool SocketStream::WriteAllAsync(
87    const void* buffer,
88    size_t size_to_write,
89    const base::Closure& success_callback,
90    const base::Callback<void(const weave::Error*)>& error_callback,
91    weave::ErrorPtr* error) {
92  chromeos::ErrorPtr chromeos_error;
93  if (!ptr_->WriteAllAsync(buffer, size_to_write, success_callback,
94                           base::Bind(&OnError, error_callback),
95                           &chromeos_error)) {
96    ConvertError(*chromeos_error, error);
97    return false;
98  }
99  return true;
100}
101
102void SocketStream::CancelPendingAsyncOperations() {
103  ptr_->CancelPendingAsyncOperations();
104}
105
106std::unique_ptr<weave::Stream> SocketStream::ConnectBlocking(
107    const std::string& host,
108    uint16_t port) {
109  int socket_fd = ConnectSocket(host, port);
110  if (socket_fd <= 0)
111    return nullptr;
112
113  auto ptr_ =
114      chromeos::FileStream::FromFileDescriptor(socket_fd, true, nullptr);
115  if (ptr_)
116    return std::unique_ptr<Stream>{new SocketStream{std::move(ptr_)}};
117
118  close(socket_fd);
119  return nullptr;
120}
121
122void SocketStream::TlsConnect(
123    std::unique_ptr<Stream> socket,
124    const std::string& host,
125    const base::Callback<void(std::unique_ptr<Stream>)>& success_callback,
126    const base::Callback<void(const weave::Error*)>& error_callback) {
127  SocketStream* stream = static_cast<SocketStream*>(socket.get());
128  chromeos::TlsStream::Connect(std::move(stream->ptr_), host,
129                               base::Bind(&OnSuccess, success_callback),
130                               base::Bind(&OnError, error_callback));
131}
132
133}  // namespace buffet
134