blob: bec0cd1b80983e62eb1a8cdd4957bf5f3834e465 [file] [log] [blame]
Vitaly Buka493f6042015-08-12 16:17:16 -07001// 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>
Alex Vakulenko71b0d782015-09-16 14:28:01 -070015#include <base/message_loop/message_loop.h>
Alex Vakulenkofa1de832015-09-29 15:51:57 -070016#include <base/strings/stringprintf.h>
Vitaly Buka493f6042015-08-12 16:17:16 -070017#include <chromeos/streams/file_stream.h>
18#include <chromeos/streams/tls_stream.h>
19
20#include "buffet/socket_stream.h"
Vitaly Buka4f771532015-08-14 14:58:39 -070021#include "buffet/weave_error_conversion.h"
Vitaly Buka493f6042015-08-12 16:17:16 -070022
23namespace buffet {
24
25namespace {
26
Alex Vakulenkofa1de832015-09-29 15:51:57 -070027std::string GetIPAddress(const sockaddr* sa) {
28 std::string addr;
29 char str[INET6_ADDRSTRLEN] = {};
30 switch (sa->sa_family) {
31 case AF_INET:
32 if (inet_ntop(AF_INET,
33 &reinterpret_cast<const sockaddr_in*>(sa)->sin_addr, str,
34 sizeof(str))) {
35 addr = str;
36 }
37 break;
38
39 case AF_INET6:
40 if (inet_ntop(AF_INET6,
41 &reinterpret_cast<const sockaddr_in6*>(sa)->sin6_addr, str,
42 sizeof(str))) {
43 addr = str;
44 }
45 break;
46 }
47 if (addr.empty())
48 addr = base::StringPrintf("<Unknown address family: %d>", sa->sa_family);
49 return addr;
50}
51
Vitaly Buka493f6042015-08-12 16:17:16 -070052int ConnectSocket(const std::string& host, uint16_t port) {
53 std::string service = std::to_string(port);
54 addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM};
55 addrinfo* result = nullptr;
56 if (getaddrinfo(host.c_str(), service.c_str(), &hints, &result)) {
57 PLOG(WARNING) << "Failed to resolve host name: " << host;
58 return -1;
59 }
60
61 int socket_fd = -1;
62 for (const addrinfo* info = result; info != nullptr; info = info->ai_next) {
63 socket_fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
64 if (socket_fd < 0)
65 continue;
66
Alex Vakulenkofa1de832015-09-29 15:51:57 -070067 std::string addr = GetIPAddress(info->ai_addr);
68 LOG(INFO) << "Connecting to address: " << addr;
Vitaly Buka493f6042015-08-12 16:17:16 -070069 if (connect(socket_fd, info->ai_addr, info->ai_addrlen) == 0)
70 break; // Success.
71
Alex Vakulenkofa1de832015-09-29 15:51:57 -070072 PLOG(WARNING) << "Failed to connect to address: " << addr;
Vitaly Buka493f6042015-08-12 16:17:16 -070073 close(socket_fd);
74 socket_fd = -1;
75 }
76
77 freeaddrinfo(result);
78 return socket_fd;
79}
80
81void OnSuccess(const base::Callback<void(std::unique_ptr<weave::Stream>)>&
82 success_callback,
83 chromeos::StreamPtr tls_stream) {
84 success_callback.Run(
85 std::unique_ptr<weave::Stream>{new SocketStream{std::move(tls_stream)}});
86}
87
Vitaly Buka4f771532015-08-14 14:58:39 -070088void OnError(const base::Callback<void(const weave::Error*)>& error_callback,
89 const chromeos::Error* chromeos_error) {
90 weave::ErrorPtr error;
91 ConvertError(*chromeos_error, &error);
92 error_callback.Run(error.get());
93}
94
Vitaly Buka493f6042015-08-12 16:17:16 -070095} // namespace
96
Alex Vakulenko0fef8152015-09-25 08:45:22 -070097void SocketStream::Read(void* buffer,
98 size_t size_to_read,
99 const ReadSuccessCallback& success_callback,
100 const weave::ErrorCallback& error_callback) {
Vitaly Buka4f771532015-08-14 14:58:39 -0700101 chromeos::ErrorPtr chromeos_error;
102 if (!ptr_->ReadAsync(buffer, size_to_read, success_callback,
103 base::Bind(&OnError, error_callback), &chromeos_error)) {
Alex Vakulenko71b0d782015-09-16 14:28:01 -0700104 weave::ErrorPtr error;
105 ConvertError(*chromeos_error, &error);
106 base::MessageLoop::current()->PostTask(
107 FROM_HERE, base::Bind(error_callback, base::Owned(error.release())));
Vitaly Buka4f771532015-08-14 14:58:39 -0700108 }
Vitaly Buka493f6042015-08-12 16:17:16 -0700109}
110
Alex Vakulenko0fef8152015-09-25 08:45:22 -0700111void SocketStream::Write(const void* buffer,
112 size_t size_to_write,
113 const weave::SuccessCallback& success_callback,
114 const weave::ErrorCallback& error_callback) {
Vitaly Buka4f771532015-08-14 14:58:39 -0700115 chromeos::ErrorPtr chromeos_error;
116 if (!ptr_->WriteAllAsync(buffer, size_to_write, success_callback,
117 base::Bind(&OnError, error_callback),
118 &chromeos_error)) {
Alex Vakulenko71b0d782015-09-16 14:28:01 -0700119 weave::ErrorPtr error;
120 ConvertError(*chromeos_error, &error);
121 base::MessageLoop::current()->PostTask(
122 FROM_HERE, base::Bind(error_callback, base::Owned(error.release())));
Vitaly Buka4f771532015-08-14 14:58:39 -0700123 }
Vitaly Buka493f6042015-08-12 16:17:16 -0700124}
125
Alex Vakulenko0fef8152015-09-25 08:45:22 -0700126void SocketStream::CancelPendingOperations() {
Vitaly Buka4f771532015-08-14 14:58:39 -0700127 ptr_->CancelPendingAsyncOperations();
Vitaly Buka493f6042015-08-12 16:17:16 -0700128}
129
130std::unique_ptr<weave::Stream> SocketStream::ConnectBlocking(
131 const std::string& host,
132 uint16_t port) {
133 int socket_fd = ConnectSocket(host, port);
134 if (socket_fd <= 0)
135 return nullptr;
136
137 auto ptr_ =
138 chromeos::FileStream::FromFileDescriptor(socket_fd, true, nullptr);
139 if (ptr_)
140 return std::unique_ptr<Stream>{new SocketStream{std::move(ptr_)}};
141
142 close(socket_fd);
143 return nullptr;
144}
145
146void SocketStream::TlsConnect(
147 std::unique_ptr<Stream> socket,
148 const std::string& host,
149 const base::Callback<void(std::unique_ptr<Stream>)>& success_callback,
Alex Vakulenko0fef8152015-09-25 08:45:22 -0700150 const weave::ErrorCallback& error_callback) {
Vitaly Buka493f6042015-08-12 16:17:16 -0700151 SocketStream* stream = static_cast<SocketStream*>(socket.get());
152 chromeos::TlsStream::Connect(std::move(stream->ptr_), host,
153 base::Bind(&OnSuccess, success_callback),
Vitaly Buka4f771532015-08-14 14:58:39 -0700154 base::Bind(&OnError, error_callback));
Vitaly Buka493f6042015-08-12 16:17:16 -0700155}
156
157} // namespace buffet