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