xref: /aosp_15_r20/external/openscreen/osp/impl/quic/quic_client.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1*3f982cf4SFabien Sanglard // Copyright 2018 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard 
5*3f982cf4SFabien Sanglard #include "osp/impl/quic/quic_client.h"
6*3f982cf4SFabien Sanglard 
7*3f982cf4SFabien Sanglard #include <algorithm>
8*3f982cf4SFabien Sanglard #include <functional>
9*3f982cf4SFabien Sanglard #include <memory>
10*3f982cf4SFabien Sanglard 
11*3f982cf4SFabien Sanglard #include "platform/api/task_runner.h"
12*3f982cf4SFabien Sanglard #include "platform/api/time.h"
13*3f982cf4SFabien Sanglard #include "util/osp_logging.h"
14*3f982cf4SFabien Sanglard 
15*3f982cf4SFabien Sanglard namespace openscreen {
16*3f982cf4SFabien Sanglard namespace osp {
17*3f982cf4SFabien Sanglard 
QuicClient(MessageDemuxer * demuxer,std::unique_ptr<QuicConnectionFactory> connection_factory,ProtocolConnectionServiceObserver * observer,ClockNowFunctionPtr now_function,TaskRunner * task_runner)18*3f982cf4SFabien Sanglard QuicClient::QuicClient(
19*3f982cf4SFabien Sanglard     MessageDemuxer* demuxer,
20*3f982cf4SFabien Sanglard     std::unique_ptr<QuicConnectionFactory> connection_factory,
21*3f982cf4SFabien Sanglard     ProtocolConnectionServiceObserver* observer,
22*3f982cf4SFabien Sanglard     ClockNowFunctionPtr now_function,
23*3f982cf4SFabien Sanglard     TaskRunner* task_runner)
24*3f982cf4SFabien Sanglard     : ProtocolConnectionClient(demuxer, observer),
25*3f982cf4SFabien Sanglard       connection_factory_(std::move(connection_factory)),
26*3f982cf4SFabien Sanglard       cleanup_alarm_(now_function, task_runner) {}
27*3f982cf4SFabien Sanglard 
~QuicClient()28*3f982cf4SFabien Sanglard QuicClient::~QuicClient() {
29*3f982cf4SFabien Sanglard   CloseAllConnections();
30*3f982cf4SFabien Sanglard }
31*3f982cf4SFabien Sanglard 
Start()32*3f982cf4SFabien Sanglard bool QuicClient::Start() {
33*3f982cf4SFabien Sanglard   if (state_ == State::kRunning)
34*3f982cf4SFabien Sanglard     return false;
35*3f982cf4SFabien Sanglard   state_ = State::kRunning;
36*3f982cf4SFabien Sanglard   Cleanup();  // Start periodic clean-ups.
37*3f982cf4SFabien Sanglard   observer_->OnRunning();
38*3f982cf4SFabien Sanglard   return true;
39*3f982cf4SFabien Sanglard }
40*3f982cf4SFabien Sanglard 
Stop()41*3f982cf4SFabien Sanglard bool QuicClient::Stop() {
42*3f982cf4SFabien Sanglard   if (state_ == State::kStopped)
43*3f982cf4SFabien Sanglard     return false;
44*3f982cf4SFabien Sanglard   CloseAllConnections();
45*3f982cf4SFabien Sanglard   state_ = State::kStopped;
46*3f982cf4SFabien Sanglard   Cleanup();  // Final clean-up.
47*3f982cf4SFabien Sanglard   observer_->OnStopped();
48*3f982cf4SFabien Sanglard   return true;
49*3f982cf4SFabien Sanglard }
50*3f982cf4SFabien Sanglard 
Cleanup()51*3f982cf4SFabien Sanglard void QuicClient::Cleanup() {
52*3f982cf4SFabien Sanglard   for (auto& entry : connections_) {
53*3f982cf4SFabien Sanglard     entry.second.delegate->DestroyClosedStreams();
54*3f982cf4SFabien Sanglard     if (!entry.second.delegate->has_streams())
55*3f982cf4SFabien Sanglard       entry.second.connection->Close();
56*3f982cf4SFabien Sanglard   }
57*3f982cf4SFabien Sanglard 
58*3f982cf4SFabien Sanglard   for (uint64_t endpoint_id : delete_connections_) {
59*3f982cf4SFabien Sanglard     auto it = connections_.find(endpoint_id);
60*3f982cf4SFabien Sanglard     if (it != connections_.end()) {
61*3f982cf4SFabien Sanglard       connections_.erase(it);
62*3f982cf4SFabien Sanglard     }
63*3f982cf4SFabien Sanglard   }
64*3f982cf4SFabien Sanglard   delete_connections_.clear();
65*3f982cf4SFabien Sanglard 
66*3f982cf4SFabien Sanglard   constexpr Clock::duration kQuicCleanupPeriod = std::chrono::milliseconds(500);
67*3f982cf4SFabien Sanglard   if (state_ != State::kStopped) {
68*3f982cf4SFabien Sanglard     cleanup_alarm_.ScheduleFromNow([this] { Cleanup(); }, kQuicCleanupPeriod);
69*3f982cf4SFabien Sanglard   }
70*3f982cf4SFabien Sanglard }
71*3f982cf4SFabien Sanglard 
Connect(const IPEndpoint & endpoint,ConnectionRequestCallback * request)72*3f982cf4SFabien Sanglard QuicClient::ConnectRequest QuicClient::Connect(
73*3f982cf4SFabien Sanglard     const IPEndpoint& endpoint,
74*3f982cf4SFabien Sanglard     ConnectionRequestCallback* request) {
75*3f982cf4SFabien Sanglard   if (state_ != State::kRunning)
76*3f982cf4SFabien Sanglard     return ConnectRequest(this, 0);
77*3f982cf4SFabien Sanglard   auto endpoint_entry = endpoint_map_.find(endpoint);
78*3f982cf4SFabien Sanglard   if (endpoint_entry != endpoint_map_.end()) {
79*3f982cf4SFabien Sanglard     auto immediate_result = CreateProtocolConnection(endpoint_entry->second);
80*3f982cf4SFabien Sanglard     OSP_DCHECK(immediate_result);
81*3f982cf4SFabien Sanglard     request->OnConnectionOpened(0, std::move(immediate_result));
82*3f982cf4SFabien Sanglard     return ConnectRequest(this, 0);
83*3f982cf4SFabien Sanglard   }
84*3f982cf4SFabien Sanglard 
85*3f982cf4SFabien Sanglard   return CreatePendingConnection(endpoint, request);
86*3f982cf4SFabien Sanglard }
87*3f982cf4SFabien Sanglard 
CreateProtocolConnection(uint64_t endpoint_id)88*3f982cf4SFabien Sanglard std::unique_ptr<ProtocolConnection> QuicClient::CreateProtocolConnection(
89*3f982cf4SFabien Sanglard     uint64_t endpoint_id) {
90*3f982cf4SFabien Sanglard   if (state_ != State::kRunning)
91*3f982cf4SFabien Sanglard     return nullptr;
92*3f982cf4SFabien Sanglard   auto connection_entry = connections_.find(endpoint_id);
93*3f982cf4SFabien Sanglard   if (connection_entry == connections_.end())
94*3f982cf4SFabien Sanglard     return nullptr;
95*3f982cf4SFabien Sanglard   return QuicProtocolConnection::FromExisting(
96*3f982cf4SFabien Sanglard       this, connection_entry->second.connection.get(),
97*3f982cf4SFabien Sanglard       connection_entry->second.delegate.get(), endpoint_id);
98*3f982cf4SFabien Sanglard }
99*3f982cf4SFabien Sanglard 
OnConnectionDestroyed(QuicProtocolConnection * connection)100*3f982cf4SFabien Sanglard void QuicClient::OnConnectionDestroyed(QuicProtocolConnection* connection) {
101*3f982cf4SFabien Sanglard   if (!connection->stream())
102*3f982cf4SFabien Sanglard     return;
103*3f982cf4SFabien Sanglard 
104*3f982cf4SFabien Sanglard   auto connection_entry = connections_.find(connection->endpoint_id());
105*3f982cf4SFabien Sanglard   if (connection_entry == connections_.end())
106*3f982cf4SFabien Sanglard     return;
107*3f982cf4SFabien Sanglard 
108*3f982cf4SFabien Sanglard   connection_entry->second.delegate->DropProtocolConnection(connection);
109*3f982cf4SFabien Sanglard }
110*3f982cf4SFabien Sanglard 
OnCryptoHandshakeComplete(ServiceConnectionDelegate * delegate,uint64_t connection_id)111*3f982cf4SFabien Sanglard uint64_t QuicClient::OnCryptoHandshakeComplete(
112*3f982cf4SFabien Sanglard     ServiceConnectionDelegate* delegate,
113*3f982cf4SFabien Sanglard     uint64_t connection_id) {
114*3f982cf4SFabien Sanglard   const IPEndpoint& endpoint = delegate->endpoint();
115*3f982cf4SFabien Sanglard   auto pending_entry = pending_connections_.find(endpoint);
116*3f982cf4SFabien Sanglard   if (pending_entry == pending_connections_.end())
117*3f982cf4SFabien Sanglard     return 0;
118*3f982cf4SFabien Sanglard 
119*3f982cf4SFabien Sanglard   ServiceConnectionData connection_data = std::move(pending_entry->second.data);
120*3f982cf4SFabien Sanglard   auto* connection = connection_data.connection.get();
121*3f982cf4SFabien Sanglard   uint64_t endpoint_id = next_endpoint_id_++;
122*3f982cf4SFabien Sanglard   endpoint_map_[endpoint] = endpoint_id;
123*3f982cf4SFabien Sanglard   connections_.emplace(endpoint_id, std::move(connection_data));
124*3f982cf4SFabien Sanglard 
125*3f982cf4SFabien Sanglard   for (auto& request : pending_entry->second.callbacks) {
126*3f982cf4SFabien Sanglard     request_map_.erase(request.first);
127*3f982cf4SFabien Sanglard     std::unique_ptr<QuicProtocolConnection> pc =
128*3f982cf4SFabien Sanglard         QuicProtocolConnection::FromExisting(this, connection, delegate,
129*3f982cf4SFabien Sanglard                                              endpoint_id);
130*3f982cf4SFabien Sanglard     request_map_.erase(request.first);
131*3f982cf4SFabien Sanglard     request.second->OnConnectionOpened(request.first, std::move(pc));
132*3f982cf4SFabien Sanglard   }
133*3f982cf4SFabien Sanglard   pending_connections_.erase(pending_entry);
134*3f982cf4SFabien Sanglard   return endpoint_id;
135*3f982cf4SFabien Sanglard }
136*3f982cf4SFabien Sanglard 
OnIncomingStream(std::unique_ptr<QuicProtocolConnection> connection)137*3f982cf4SFabien Sanglard void QuicClient::OnIncomingStream(
138*3f982cf4SFabien Sanglard     std::unique_ptr<QuicProtocolConnection> connection) {
139*3f982cf4SFabien Sanglard   // TODO(jophba): Change to just use OnIncomingConnection when the observer
140*3f982cf4SFabien Sanglard   // is properly set up.
141*3f982cf4SFabien Sanglard   connection->CloseWriteEnd();
142*3f982cf4SFabien Sanglard   connection.reset();
143*3f982cf4SFabien Sanglard }
144*3f982cf4SFabien Sanglard 
OnConnectionClosed(uint64_t endpoint_id,uint64_t connection_id)145*3f982cf4SFabien Sanglard void QuicClient::OnConnectionClosed(uint64_t endpoint_id,
146*3f982cf4SFabien Sanglard                                     uint64_t connection_id) {
147*3f982cf4SFabien Sanglard   // TODO(btolsch): Is this how handshake failure is communicated to the
148*3f982cf4SFabien Sanglard   // delegate?
149*3f982cf4SFabien Sanglard   auto connection_entry = connections_.find(endpoint_id);
150*3f982cf4SFabien Sanglard   if (connection_entry == connections_.end())
151*3f982cf4SFabien Sanglard     return;
152*3f982cf4SFabien Sanglard   delete_connections_.push_back(endpoint_id);
153*3f982cf4SFabien Sanglard 
154*3f982cf4SFabien Sanglard   // TODO(crbug.com/openscreen/42): If we reset request IDs when a connection is
155*3f982cf4SFabien Sanglard   // closed, we might end up re-using request IDs when a new connection is
156*3f982cf4SFabien Sanglard   // created to the same endpoint.
157*3f982cf4SFabien Sanglard   endpoint_request_ids_.ResetRequestId(endpoint_id);
158*3f982cf4SFabien Sanglard }
159*3f982cf4SFabien Sanglard 
OnDataReceived(uint64_t endpoint_id,uint64_t connection_id,const uint8_t * data,size_t data_size)160*3f982cf4SFabien Sanglard void QuicClient::OnDataReceived(uint64_t endpoint_id,
161*3f982cf4SFabien Sanglard                                 uint64_t connection_id,
162*3f982cf4SFabien Sanglard                                 const uint8_t* data,
163*3f982cf4SFabien Sanglard                                 size_t data_size) {
164*3f982cf4SFabien Sanglard   demuxer_->OnStreamData(endpoint_id, connection_id, data, data_size);
165*3f982cf4SFabien Sanglard }
166*3f982cf4SFabien Sanglard 
PendingConnectionData(ServiceConnectionData && data)167*3f982cf4SFabien Sanglard QuicClient::PendingConnectionData::PendingConnectionData(
168*3f982cf4SFabien Sanglard     ServiceConnectionData&& data)
169*3f982cf4SFabien Sanglard     : data(std::move(data)) {}
170*3f982cf4SFabien Sanglard QuicClient::PendingConnectionData::PendingConnectionData(
171*3f982cf4SFabien Sanglard     PendingConnectionData&&) noexcept = default;
172*3f982cf4SFabien Sanglard QuicClient::PendingConnectionData::~PendingConnectionData() = default;
173*3f982cf4SFabien Sanglard QuicClient::PendingConnectionData& QuicClient::PendingConnectionData::operator=(
174*3f982cf4SFabien Sanglard     PendingConnectionData&&) noexcept = default;
175*3f982cf4SFabien Sanglard 
CreatePendingConnection(const IPEndpoint & endpoint,ConnectionRequestCallback * request)176*3f982cf4SFabien Sanglard QuicClient::ConnectRequest QuicClient::CreatePendingConnection(
177*3f982cf4SFabien Sanglard     const IPEndpoint& endpoint,
178*3f982cf4SFabien Sanglard     ConnectionRequestCallback* request) {
179*3f982cf4SFabien Sanglard   auto pending_entry = pending_connections_.find(endpoint);
180*3f982cf4SFabien Sanglard   if (pending_entry == pending_connections_.end()) {
181*3f982cf4SFabien Sanglard     uint64_t request_id = StartConnectionRequest(endpoint, request);
182*3f982cf4SFabien Sanglard     return ConnectRequest(this, request_id);
183*3f982cf4SFabien Sanglard   } else {
184*3f982cf4SFabien Sanglard     uint64_t request_id = next_request_id_++;
185*3f982cf4SFabien Sanglard     pending_entry->second.callbacks.emplace_back(request_id, request);
186*3f982cf4SFabien Sanglard     return ConnectRequest(this, request_id);
187*3f982cf4SFabien Sanglard   }
188*3f982cf4SFabien Sanglard }
189*3f982cf4SFabien Sanglard 
StartConnectionRequest(const IPEndpoint & endpoint,ConnectionRequestCallback * request)190*3f982cf4SFabien Sanglard uint64_t QuicClient::StartConnectionRequest(
191*3f982cf4SFabien Sanglard     const IPEndpoint& endpoint,
192*3f982cf4SFabien Sanglard     ConnectionRequestCallback* request) {
193*3f982cf4SFabien Sanglard   auto delegate = std::make_unique<ServiceConnectionDelegate>(this, endpoint);
194*3f982cf4SFabien Sanglard   std::unique_ptr<QuicConnection> connection =
195*3f982cf4SFabien Sanglard       connection_factory_->Connect(endpoint, delegate.get());
196*3f982cf4SFabien Sanglard   if (!connection) {
197*3f982cf4SFabien Sanglard     // TODO(btolsch): Need interface/handling for Connect() failures. Or, should
198*3f982cf4SFabien Sanglard     // request->OnConnectionFailed() be called?
199*3f982cf4SFabien Sanglard     OSP_DCHECK(false)
200*3f982cf4SFabien Sanglard         << __func__
201*3f982cf4SFabien Sanglard         << ": Factory connect failed, but requestor will never know.";
202*3f982cf4SFabien Sanglard     return 0;
203*3f982cf4SFabien Sanglard   }
204*3f982cf4SFabien Sanglard   auto pending_result = pending_connections_.emplace(
205*3f982cf4SFabien Sanglard       endpoint, PendingConnectionData(ServiceConnectionData(
206*3f982cf4SFabien Sanglard                     std::move(connection), std::move(delegate))));
207*3f982cf4SFabien Sanglard   uint64_t request_id = next_request_id_++;
208*3f982cf4SFabien Sanglard   pending_result.first->second.callbacks.emplace_back(request_id, request);
209*3f982cf4SFabien Sanglard   return request_id;
210*3f982cf4SFabien Sanglard }
211*3f982cf4SFabien Sanglard 
CloseAllConnections()212*3f982cf4SFabien Sanglard void QuicClient::CloseAllConnections() {
213*3f982cf4SFabien Sanglard   for (auto& conn : pending_connections_)
214*3f982cf4SFabien Sanglard     conn.second.data.connection->Close();
215*3f982cf4SFabien Sanglard 
216*3f982cf4SFabien Sanglard   pending_connections_.clear();
217*3f982cf4SFabien Sanglard   for (auto& conn : connections_)
218*3f982cf4SFabien Sanglard     conn.second.connection->Close();
219*3f982cf4SFabien Sanglard 
220*3f982cf4SFabien Sanglard   connections_.clear();
221*3f982cf4SFabien Sanglard   endpoint_map_.clear();
222*3f982cf4SFabien Sanglard   next_endpoint_id_ = 0;
223*3f982cf4SFabien Sanglard   endpoint_request_ids_.Reset();
224*3f982cf4SFabien Sanglard   for (auto& request : request_map_) {
225*3f982cf4SFabien Sanglard     request.second.second->OnConnectionFailed(request.first);
226*3f982cf4SFabien Sanglard   }
227*3f982cf4SFabien Sanglard   request_map_.clear();
228*3f982cf4SFabien Sanglard }
229*3f982cf4SFabien Sanglard 
CancelConnectRequest(uint64_t request_id)230*3f982cf4SFabien Sanglard void QuicClient::CancelConnectRequest(uint64_t request_id) {
231*3f982cf4SFabien Sanglard   auto request_entry = request_map_.find(request_id);
232*3f982cf4SFabien Sanglard   if (request_entry == request_map_.end())
233*3f982cf4SFabien Sanglard     return;
234*3f982cf4SFabien Sanglard 
235*3f982cf4SFabien Sanglard   auto pending_entry = pending_connections_.find(request_entry->second.first);
236*3f982cf4SFabien Sanglard   if (pending_entry != pending_connections_.end()) {
237*3f982cf4SFabien Sanglard     auto& callbacks = pending_entry->second.callbacks;
238*3f982cf4SFabien Sanglard     callbacks.erase(
239*3f982cf4SFabien Sanglard         std::remove_if(
240*3f982cf4SFabien Sanglard             callbacks.begin(), callbacks.end(),
241*3f982cf4SFabien Sanglard             [request_id](const std::pair<uint64_t, ConnectionRequestCallback*>&
242*3f982cf4SFabien Sanglard                              callback) {
243*3f982cf4SFabien Sanglard               return request_id == callback.first;
244*3f982cf4SFabien Sanglard             }),
245*3f982cf4SFabien Sanglard         callbacks.end());
246*3f982cf4SFabien Sanglard     if (callbacks.empty())
247*3f982cf4SFabien Sanglard       pending_connections_.erase(pending_entry);
248*3f982cf4SFabien Sanglard   }
249*3f982cf4SFabien Sanglard   request_map_.erase(request_entry);
250*3f982cf4SFabien Sanglard }
251*3f982cf4SFabien Sanglard 
252*3f982cf4SFabien Sanglard }  // namespace osp
253*3f982cf4SFabien Sanglard }  // namespace openscreen
254