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