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