• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_connection_factory_impl.h"
6 
7 #include <algorithm>
8 #include <memory>
9 
10 #include "osp/impl/quic/quic_connection_impl.h"
11 #include "platform/api/task_runner.h"
12 #include "platform/api/time.h"
13 #include "platform/base/error.h"
14 #include "third_party/chromium_quic/src/base/location.h"
15 #include "third_party/chromium_quic/src/base/task_runner.h"
16 #include "third_party/chromium_quic/src/net/third_party/quic/core/quic_constants.h"
17 #include "third_party/chromium_quic/src/net/third_party/quic/platform/impl/quic_chromium_clock.h"
18 #include "util/osp_logging.h"
19 #include "util/trace_logging.h"
20 
21 namespace openscreen {
22 namespace osp {
23 
24 class QuicTaskRunner final : public ::base::TaskRunner {
25  public:
26   explicit QuicTaskRunner(openscreen::TaskRunner* task_runner);
27   ~QuicTaskRunner() override;
28 
29   void RunTasks();
30 
31   // base::TaskRunner overrides.
32   bool PostDelayedTask(const ::base::Location& whence,
33                        ::base::OnceClosure task,
34                        ::base::TimeDelta delay) override;
35 
36   bool RunsTasksInCurrentSequence() const override;
37 
38  private:
39   openscreen::TaskRunner* const task_runner_;
40 };
41 
QuicTaskRunner(openscreen::TaskRunner * task_runner)42 QuicTaskRunner::QuicTaskRunner(openscreen::TaskRunner* task_runner)
43     : task_runner_(task_runner) {}
44 
45 QuicTaskRunner::~QuicTaskRunner() = default;
46 
RunTasks()47 void QuicTaskRunner::RunTasks() {}
48 
PostDelayedTask(const::base::Location & whence,::base::OnceClosure task,::base::TimeDelta delay)49 bool QuicTaskRunner::PostDelayedTask(const ::base::Location& whence,
50                                      ::base::OnceClosure task,
51                                      ::base::TimeDelta delay) {
52   Clock::duration wait = Clock::duration(delay.InMilliseconds());
53   task_runner_->PostTaskWithDelay(
54       [closure = std::move(task)]() mutable { std::move(closure).Run(); },
55       wait);
56   return true;
57 }
58 
RunsTasksInCurrentSequence() const59 bool QuicTaskRunner::RunsTasksInCurrentSequence() const {
60   return true;
61 }
62 
QuicConnectionFactoryImpl(TaskRunner * task_runner)63 QuicConnectionFactoryImpl::QuicConnectionFactoryImpl(TaskRunner* task_runner)
64     : task_runner_(task_runner) {
65   quic_task_runner_ = ::base::MakeRefCounted<QuicTaskRunner>(task_runner);
66   alarm_factory_ = std::make_unique<::net::QuicChromiumAlarmFactory>(
67       quic_task_runner_.get(), ::quic::QuicChromiumClock::GetInstance());
68   ::quic::QuartcFactoryConfig factory_config;
69   factory_config.alarm_factory = alarm_factory_.get();
70   factory_config.clock = ::quic::QuicChromiumClock::GetInstance();
71   quartc_factory_ = std::make_unique<::quic::QuartcFactory>(factory_config);
72 }
73 
~QuicConnectionFactoryImpl()74 QuicConnectionFactoryImpl::~QuicConnectionFactoryImpl() {
75   OSP_DCHECK(connections_.empty());
76 }
77 
SetServerDelegate(ServerDelegate * delegate,const std::vector<IPEndpoint> & endpoints)78 void QuicConnectionFactoryImpl::SetServerDelegate(
79     ServerDelegate* delegate,
80     const std::vector<IPEndpoint>& endpoints) {
81   OSP_DCHECK(!delegate != !server_delegate_);
82 
83   server_delegate_ = delegate;
84   sockets_.reserve(sockets_.size() + endpoints.size());
85 
86   for (const auto& endpoint : endpoints) {
87     // TODO(mfoltz): Need to notify the caller and/or ServerDelegate if socket
88     // create/bind errors occur. Maybe return an Error immediately, and undo
89     // partial progress (i.e. "unwatch" all the sockets and call
90     // sockets_.clear() to close the sockets)?
91     auto create_result = UdpSocket::Create(task_runner_, this, endpoint);
92     if (!create_result) {
93       OSP_LOG_ERROR << "failed to create socket (for " << endpoint
94                     << "): " << create_result.error().message();
95       continue;
96     }
97     std::unique_ptr<UdpSocket> server_socket = std::move(create_result.value());
98     server_socket->Bind();
99     sockets_.emplace_back(std::move(server_socket));
100   }
101 }
102 
OnRead(UdpSocket * socket,ErrorOr<UdpPacket> packet_or_error)103 void QuicConnectionFactoryImpl::OnRead(UdpSocket* socket,
104                                        ErrorOr<UdpPacket> packet_or_error) {
105   TRACE_SCOPED(TraceCategory::kQuic, "QuicConnectionFactoryImpl::OnRead");
106   if (packet_or_error.is_error()) {
107     return;
108   }
109 
110   UdpPacket packet = std::move(packet_or_error.value());
111   // Ensure that |packet.socket| is one of the instances owned by
112   // QuicConnectionFactoryImpl.
113   auto packet_ptr = &packet;
114   OSP_DCHECK(std::find_if(sockets_.begin(), sockets_.end(),
115                           [packet_ptr](const std::unique_ptr<UdpSocket>& s) {
116                             return s.get() == packet_ptr->socket();
117                           }) != sockets_.end());
118 
119   // TODO(btolsch): We will need to rethink this both for ICE and connection
120   // migration support.
121   auto conn_it = connections_.find(packet.source());
122   if (conn_it == connections_.end()) {
123     if (server_delegate_) {
124       OSP_VLOG << __func__ << ": spawning connection from " << packet.source();
125       auto transport =
126           std::make_unique<UdpTransport>(packet.socket(), packet.source());
127       ::quic::QuartcSessionConfig session_config;
128       session_config.perspective = ::quic::Perspective::IS_SERVER;
129       session_config.packet_transport = transport.get();
130 
131       auto result = std::make_unique<QuicConnectionImpl>(
132           this, server_delegate_->NextConnectionDelegate(packet.source()),
133           std::move(transport),
134           quartc_factory_->CreateQuartcSession(session_config));
135       auto* result_ptr = result.get();
136       connections_.emplace(packet.source(),
137                            OpenConnection{result_ptr, packet.socket()});
138       server_delegate_->OnIncomingConnection(std::move(result));
139       result_ptr->OnRead(socket, std::move(packet));
140     }
141   } else {
142     OSP_VLOG << __func__ << ": data for existing connection from "
143              << packet.source();
144     conn_it->second.connection->OnRead(socket, std::move(packet));
145   }
146 }
147 
Connect(const IPEndpoint & endpoint,QuicConnection::Delegate * connection_delegate)148 std::unique_ptr<QuicConnection> QuicConnectionFactoryImpl::Connect(
149     const IPEndpoint& endpoint,
150     QuicConnection::Delegate* connection_delegate) {
151   auto create_result = UdpSocket::Create(task_runner_, this, endpoint);
152   if (!create_result) {
153     OSP_LOG_ERROR << "failed to create socket: "
154                   << create_result.error().message();
155     // TODO(mfoltz): This method should return ErrorOr<uni_ptr<QuicConnection>>.
156     return nullptr;
157   }
158   std::unique_ptr<UdpSocket> socket = std::move(create_result.value());
159   auto transport = std::make_unique<UdpTransport>(socket.get(), endpoint);
160 
161   ::quic::QuartcSessionConfig session_config;
162   session_config.perspective = ::quic::Perspective::IS_CLIENT;
163   // TODO(btolsch): Proper server id.  Does this go in the QUIC server name
164   // parameter?
165   session_config.unique_remote_server_id = "turtle";
166   session_config.packet_transport = transport.get();
167 
168   auto result = std::make_unique<QuicConnectionImpl>(
169       this, connection_delegate, std::move(transport),
170       quartc_factory_->CreateQuartcSession(session_config));
171 
172   // TODO(btolsch): This presents a problem for multihomed receivers, which may
173   // register as a different endpoint in their response.  I think QUIC is
174   // already tolerant of this via connection IDs but this hasn't been tested
175   // (and even so, those aren't necessarily stable either).
176   connections_.emplace(endpoint, OpenConnection{result.get(), socket.get()});
177   sockets_.emplace_back(std::move(socket));
178 
179   return result;
180 }
181 
OnConnectionClosed(QuicConnection * connection)182 void QuicConnectionFactoryImpl::OnConnectionClosed(QuicConnection* connection) {
183   auto entry = std::find_if(
184       connections_.begin(), connections_.end(),
185       [connection](const decltype(connections_)::value_type& entry) {
186         return entry.second.connection == connection;
187       });
188   OSP_DCHECK(entry != connections_.end());
189   UdpSocket* const socket = entry->second.socket;
190   connections_.erase(entry);
191 
192   // If none of the remaining |connections_| reference the socket, close/destroy
193   // it.
194   if (std::find_if(connections_.begin(), connections_.end(),
195                    [socket](const decltype(connections_)::value_type& entry) {
196                      return entry.second.socket == socket;
197                    }) == connections_.end()) {
198     auto socket_it =
199         std::find_if(sockets_.begin(), sockets_.end(),
200                      [socket](const std::unique_ptr<UdpSocket>& s) {
201                        return s.get() == socket;
202                      });
203     OSP_DCHECK(socket_it != sockets_.end());
204     sockets_.erase(socket_it);
205   }
206 }
207 
OnError(UdpSocket * socket,Error error)208 void QuicConnectionFactoryImpl::OnError(UdpSocket* socket, Error error) {
209   OSP_LOG_ERROR << "failed to configure socket " << error.message();
210 }
211 
OnSendError(UdpSocket * socket,Error error)212 void QuicConnectionFactoryImpl::OnSendError(UdpSocket* socket, Error error) {
213   // TODO(crbug.com/openscreen/67): Implement this method.
214   OSP_UNIMPLEMENTED();
215 }
216 
217 }  // namespace osp
218 }  // namespace openscreen
219