1 // Copyright 2018 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 "osp/impl/quic/quic_server.h"
6
7 #include <functional>
8 #include <memory>
9
10 #include "platform/api/task_runner.h"
11 #include "platform/api/time.h"
12 #include "util/osp_logging.h"
13
14 namespace openscreen {
15 namespace osp {
16
QuicServer(const ServerConfig & config,MessageDemuxer * demuxer,std::unique_ptr<QuicConnectionFactory> connection_factory,ProtocolConnectionServer::Observer * observer,ClockNowFunctionPtr now_function,TaskRunner * task_runner)17 QuicServer::QuicServer(
18 const ServerConfig& config,
19 MessageDemuxer* demuxer,
20 std::unique_ptr<QuicConnectionFactory> connection_factory,
21 ProtocolConnectionServer::Observer* observer,
22 ClockNowFunctionPtr now_function,
23 TaskRunner* task_runner)
24 : ProtocolConnectionServer(demuxer, observer),
25 connection_endpoints_(config.connection_endpoints),
26 connection_factory_(std::move(connection_factory)),
27 cleanup_alarm_(now_function, task_runner) {}
28
~QuicServer()29 QuicServer::~QuicServer() {
30 CloseAllConnections();
31 }
32
Start()33 bool QuicServer::Start() {
34 if (state_ != State::kStopped)
35 return false;
36 state_ = State::kRunning;
37 connection_factory_->SetServerDelegate(this, connection_endpoints_);
38 Cleanup(); // Start periodic clean-ups.
39 observer_->OnRunning();
40 return true;
41 }
42
Stop()43 bool QuicServer::Stop() {
44 if (state_ != State::kRunning && state_ != State::kSuspended)
45 return false;
46 connection_factory_->SetServerDelegate(nullptr, {});
47 CloseAllConnections();
48 state_ = State::kStopped;
49 Cleanup(); // Final clean-up.
50 observer_->OnStopped();
51 return true;
52 }
53
Suspend()54 bool QuicServer::Suspend() {
55 // TODO(btolsch): QuicStreams should either buffer or reject writes.
56 if (state_ != State::kRunning)
57 return false;
58 state_ = State::kSuspended;
59 observer_->OnSuspended();
60 return true;
61 }
62
Resume()63 bool QuicServer::Resume() {
64 if (state_ != State::kSuspended)
65 return false;
66 state_ = State::kRunning;
67 observer_->OnRunning();
68 return true;
69 }
70
Cleanup()71 void QuicServer::Cleanup() {
72 for (auto& entry : connections_)
73 entry.second.delegate->DestroyClosedStreams();
74
75 for (uint64_t endpoint_id : delete_connections_) {
76 auto it = connections_.find(endpoint_id);
77 if (it != connections_.end()) {
78 connections_.erase(it);
79 }
80 }
81 delete_connections_.clear();
82
83 constexpr Clock::duration kQuicCleanupPeriod = std::chrono::milliseconds(500);
84 if (state_ != State::kStopped) {
85 cleanup_alarm_.ScheduleFromNow([this] { Cleanup(); }, kQuicCleanupPeriod);
86 }
87 }
88
CreateProtocolConnection(uint64_t endpoint_id)89 std::unique_ptr<ProtocolConnection> QuicServer::CreateProtocolConnection(
90 uint64_t endpoint_id) {
91 if (state_ != State::kRunning) {
92 return nullptr;
93 }
94 auto connection_entry = connections_.find(endpoint_id);
95 if (connection_entry == connections_.end()) {
96 return nullptr;
97 }
98 return QuicProtocolConnection::FromExisting(
99 this, connection_entry->second.connection.get(),
100 connection_entry->second.delegate.get(), endpoint_id);
101 }
102
OnConnectionDestroyed(QuicProtocolConnection * connection)103 void QuicServer::OnConnectionDestroyed(QuicProtocolConnection* connection) {
104 if (!connection->stream())
105 return;
106
107 auto connection_entry = connections_.find(connection->endpoint_id());
108 if (connection_entry == connections_.end())
109 return;
110
111 connection_entry->second.delegate->DropProtocolConnection(connection);
112 }
113
OnCryptoHandshakeComplete(ServiceConnectionDelegate * delegate,uint64_t connection_id)114 uint64_t QuicServer::OnCryptoHandshakeComplete(
115 ServiceConnectionDelegate* delegate,
116 uint64_t connection_id) {
117 OSP_DCHECK_EQ(state_, State::kRunning);
118 const IPEndpoint& endpoint = delegate->endpoint();
119 auto pending_entry = pending_connections_.find(endpoint);
120 if (pending_entry == pending_connections_.end())
121 return 0;
122 ServiceConnectionData connection_data = std::move(pending_entry->second);
123 pending_connections_.erase(pending_entry);
124 uint64_t endpoint_id = next_endpoint_id_++;
125 endpoint_map_[endpoint] = endpoint_id;
126 connections_.emplace(endpoint_id, std::move(connection_data));
127 return endpoint_id;
128 }
129
OnIncomingStream(std::unique_ptr<QuicProtocolConnection> connection)130 void QuicServer::OnIncomingStream(
131 std::unique_ptr<QuicProtocolConnection> connection) {
132 OSP_DCHECK_EQ(state_, State::kRunning);
133 observer_->OnIncomingConnection(std::move(connection));
134 }
135
OnConnectionClosed(uint64_t endpoint_id,uint64_t connection_id)136 void QuicServer::OnConnectionClosed(uint64_t endpoint_id,
137 uint64_t connection_id) {
138 OSP_DCHECK_EQ(state_, State::kRunning);
139 auto connection_entry = connections_.find(endpoint_id);
140 if (connection_entry == connections_.end())
141 return;
142 delete_connections_.push_back(endpoint_id);
143
144 // TODO(crbug.com/openscreen/42): If we reset request IDs when a connection is
145 // closed, we might end up re-using request IDs when a new connection is
146 // created to the same endpoint.
147 endpoint_request_ids_.ResetRequestId(endpoint_id);
148 }
149
OnDataReceived(uint64_t endpoint_id,uint64_t connection_id,const uint8_t * data,size_t data_size)150 void QuicServer::OnDataReceived(uint64_t endpoint_id,
151 uint64_t connection_id,
152 const uint8_t* data,
153 size_t data_size) {
154 OSP_DCHECK_EQ(state_, State::kRunning);
155 demuxer_->OnStreamData(endpoint_id, connection_id, data, data_size);
156 }
157
CloseAllConnections()158 void QuicServer::CloseAllConnections() {
159 for (auto& conn : pending_connections_)
160 conn.second.connection->Close();
161
162 pending_connections_.clear();
163
164 for (auto& conn : connections_)
165 conn.second.connection->Close();
166
167 connections_.clear();
168 endpoint_map_.clear();
169 next_endpoint_id_ = 0;
170 endpoint_request_ids_.Reset();
171 }
172
NextConnectionDelegate(const IPEndpoint & source)173 QuicConnection::Delegate* QuicServer::NextConnectionDelegate(
174 const IPEndpoint& source) {
175 OSP_DCHECK_EQ(state_, State::kRunning);
176 OSP_DCHECK(!pending_connection_delegate_);
177 pending_connection_delegate_ =
178 std::make_unique<ServiceConnectionDelegate>(this, source);
179 return pending_connection_delegate_.get();
180 }
181
OnIncomingConnection(std::unique_ptr<QuicConnection> connection)182 void QuicServer::OnIncomingConnection(
183 std::unique_ptr<QuicConnection> connection) {
184 OSP_DCHECK_EQ(state_, State::kRunning);
185 const IPEndpoint& endpoint = pending_connection_delegate_->endpoint();
186 pending_connections_.emplace(
187 endpoint, ServiceConnectionData(std::move(connection),
188 std::move(pending_connection_delegate_)));
189 }
190
191 } // namespace osp
192 } // namespace openscreen
193