1 // Copyright 2019 The Chromium 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 "platform/impl/tls_connection_posix.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <netinet/in.h>
10 #include <netinet/ip.h>
11 #include <openssl/ssl.h>
12 #include <sys/ioctl.h>
13 #include <sys/socket.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16
17 #include <cstring>
18 #include <memory>
19 #include <utility>
20 #include <vector>
21
22 #include "absl/types/optional.h"
23 #include "absl/types/span.h"
24 #include "platform/api/task_runner.h"
25 #include "platform/base/error.h"
26 #include "platform/impl/stream_socket.h"
27 #include "util/crypto/openssl_util.h"
28 #include "util/osp_logging.h"
29
30 namespace openscreen {
31
32 // TODO(jophba, rwkeane): implement write blocking/unblocking
TlsConnectionPosix(IPEndpoint local_address,TaskRunner * task_runner)33 TlsConnectionPosix::TlsConnectionPosix(IPEndpoint local_address,
34 TaskRunner* task_runner)
35 : task_runner_(task_runner),
36 socket_(std::make_unique<StreamSocketPosix>(local_address)) {
37 OSP_DCHECK(task_runner_);
38 }
39
TlsConnectionPosix(IPAddress::Version version,TaskRunner * task_runner)40 TlsConnectionPosix::TlsConnectionPosix(IPAddress::Version version,
41 TaskRunner* task_runner)
42 : task_runner_(task_runner),
43 socket_(std::make_unique<StreamSocketPosix>(version)) {
44 OSP_DCHECK(task_runner_);
45 }
46
TlsConnectionPosix(std::unique_ptr<StreamSocket> socket,TaskRunner * task_runner)47 TlsConnectionPosix::TlsConnectionPosix(std::unique_ptr<StreamSocket> socket,
48 TaskRunner* task_runner)
49 : task_runner_(task_runner), socket_(std::move(socket)) {
50 OSP_DCHECK(task_runner_);
51 }
52
~TlsConnectionPosix()53 TlsConnectionPosix::~TlsConnectionPosix() {
54 if (platform_client_) {
55 platform_client_->tls_data_router()->DeregisterConnection(this);
56 }
57 // TODO(issuetracker.google.com/169966671): This is only tested by CastSocket
58 // E2E tests at the moment.
59 if (ssl_) {
60 SSL_shutdown(ssl_.get());
61 }
62 }
63
TryReceiveMessage()64 void TlsConnectionPosix::TryReceiveMessage() {
65 OSP_DCHECK(ssl_);
66 constexpr int kMaxApplicationDataBytes = 4096;
67 std::vector<uint8_t> block(kMaxApplicationDataBytes);
68 ClearOpenSSLERRStack(CURRENT_LOCATION);
69 const int bytes_read =
70 SSL_read(ssl_.get(), block.data(), kMaxApplicationDataBytes);
71
72 // Read operator was not successful, either due to a closed connection,
73 // no application data available, an error occurred, or we have to take an
74 // action.
75 if (bytes_read <= 0) {
76 const Error error = GetSSLError(ssl_.get(), bytes_read);
77 if (!error.ok() && (error != Error::Code::kAgain)) {
78 DispatchError(error);
79 }
80 return;
81 }
82
83 block.resize(bytes_read);
84
85 task_runner_->PostTask([weak_this = weak_factory_.GetWeakPtr(),
86 moved_block = std::move(block)]() mutable {
87 if (auto* self = weak_this.get()) {
88 if (auto* client = self->client_) {
89 client->OnRead(self, std::move(moved_block));
90 }
91 }
92 });
93 }
94
SetClient(Client * client)95 void TlsConnectionPosix::SetClient(Client* client) {
96 OSP_DCHECK(task_runner_->IsRunningOnTaskRunner());
97 client_ = client;
98 }
99
Send(const void * data,size_t len)100 bool TlsConnectionPosix::Send(const void* data, size_t len) {
101 OSP_DCHECK(task_runner_->IsRunningOnTaskRunner());
102 return buffer_.Push(data, len);
103 }
104
GetLocalEndpoint() const105 IPEndpoint TlsConnectionPosix::GetLocalEndpoint() const {
106 OSP_DCHECK(task_runner_->IsRunningOnTaskRunner());
107
108 absl::optional<IPEndpoint> endpoint = socket_->local_address();
109 OSP_DCHECK(endpoint.has_value());
110 return endpoint.value();
111 }
112
GetRemoteEndpoint() const113 IPEndpoint TlsConnectionPosix::GetRemoteEndpoint() const {
114 OSP_DCHECK(task_runner_->IsRunningOnTaskRunner());
115
116 absl::optional<IPEndpoint> endpoint = socket_->remote_address();
117 OSP_DCHECK(endpoint.has_value());
118 return endpoint.value();
119 }
120
RegisterConnectionWithDataRouter(PlatformClientPosix * platform_client)121 void TlsConnectionPosix::RegisterConnectionWithDataRouter(
122 PlatformClientPosix* platform_client) {
123 OSP_DCHECK(!platform_client_);
124 platform_client_ = platform_client;
125 platform_client_->tls_data_router()->RegisterConnection(this);
126 }
127
SendAvailableBytes()128 void TlsConnectionPosix::SendAvailableBytes() {
129 absl::Span<const uint8_t> sendable_bytes = buffer_.GetReadableRegion();
130 if (sendable_bytes.empty()) {
131 return;
132 }
133
134 ClearOpenSSLERRStack(CURRENT_LOCATION);
135 const int result =
136 SSL_write(ssl_.get(), sendable_bytes.data(), sendable_bytes.size());
137 if (result <= 0) {
138 const Error result_error = GetSSLError(ssl_.get(), result);
139 if (!result_error.ok() && (result_error.code() != Error::Code::kAgain)) {
140 DispatchError(result_error);
141 }
142 } else {
143 buffer_.Consume(static_cast<size_t>(result));
144 }
145 }
146
DispatchError(Error error)147 void TlsConnectionPosix::DispatchError(Error error) {
148 task_runner_->PostTask([weak_this = weak_factory_.GetWeakPtr(),
149 moved_error = std::move(error)]() mutable {
150 if (auto* self = weak_this.get()) {
151 if (auto* client = self->client_) {
152 client->OnError(self, std::move(moved_error));
153 }
154 }
155 });
156 }
157
158 } // namespace openscreen
159