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