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