66
77#include " source/common/network/socket_option_factory.h"
88#include " source/common/network/udp_packet_writer_handler_impl.h"
9- #include " source/common/quic/envoy_quic_utils.h"
109#include " source/common/runtime/runtime_features.h"
1110
1211namespace Envoy {
@@ -24,29 +23,107 @@ class DeferredDeletableSocket : public Event::DeferredDeletable {
2423 std::unique_ptr<Network::ConnectionSocket> socket_;
2524};
2625
27- EnvoyQuicClientConnection::EnvoyQuicClientConnection (
28- const quic::QuicConnectionId& server_connection_id,
29- Network::Address::InstanceConstSharedPtr& initial_peer_address,
30- quic::QuicConnectionHelperInterface& helper, quic::QuicAlarmFactory& alarm_factory,
31- const quic::ParsedQuicVersionVector& supported_versions,
32- Network::Address::InstanceConstSharedPtr local_addr, Event::Dispatcher& dispatcher,
33- const Network::ConnectionSocket::OptionsSharedPtr& options,
34- quic::ConnectionIdGeneratorInterface& generator)
35- : EnvoyQuicClientConnection(
36- server_connection_id, helper, alarm_factory, supported_versions, dispatcher,
37- createConnectionSocket (initial_peer_address, local_addr, options), generator) {}
26+ class EnvoyQuicClientPathValidationContext : public quic ::QuicClientPathValidationContext {
27+ public:
28+ EnvoyQuicClientPathValidationContext (quic::QuicSocketAddress self_address,
29+ quic::QuicSocketAddress peer_address,
30+ quic::QuicNetworkHandle network,
31+ std::unique_ptr<EnvoyQuicPacketWriter>&& writer,
32+ Network::ConnectionSocketPtr&& socket,
33+ Event::Dispatcher& dispatcher)
34+ : quic::QuicClientPathValidationContext(self_address, peer_address, network),
35+ writer_ (std::make_unique<quic::QuicForceBlockablePacketWriter>()),
36+ socket_(std::move(socket)), dispatcher_(dispatcher) {
37+ // Owns the writer.
38+ writer_->set_writer (writer.release ());
39+ }
3840
39- EnvoyQuicClientConnection::EnvoyQuicClientConnection (
40- const quic::QuicConnectionId& server_connection_id, quic::QuicConnectionHelperInterface& helper,
41- quic::QuicAlarmFactory& alarm_factory, const quic::ParsedQuicVersionVector& supported_versions,
42- Event::Dispatcher& dispatcher, Network::ConnectionSocketPtr&& connection_socket,
43- quic::ConnectionIdGeneratorInterface& generator)
44- : EnvoyQuicClientConnection(
45- server_connection_id, helper, alarm_factory,
46- new EnvoyQuicPacketWriter(
47- std::make_unique<Network::UdpDefaultWriter>(connection_socket->ioHandle ())),
48- /* owns_writer=*/ true, supported_versions, dispatcher, std::move(connection_socket),
49- generator) {}
41+ ~EnvoyQuicClientPathValidationContext () override {
42+ if (socket_ != nullptr ) {
43+ // The socket wasn't used by the connection, the path validation must have failed. Now
44+ // deferred delete it to avoid deleting IoHandle in a read loop.
45+ dispatcher_.deferredDelete (std::make_unique<DeferredDeletableSocket>(std::move (socket_)));
46+ }
47+ }
48+
49+ bool ShouldConnectionOwnWriter () const override { return true ; }
50+ quic::QuicForceBlockablePacketWriter* ForceBlockableWriterToUse () override {
51+ return writer_.get ();
52+ }
53+
54+ Network::ConnectionSocket& probingSocket () { return *socket_; }
55+
56+ quic::QuicForceBlockablePacketWriter* releaseWriter () { return writer_.release (); }
57+ std::unique_ptr<Network::ConnectionSocket> releaseSocket () { return std::move (socket_); }
58+
59+ private:
60+ std::unique_ptr<quic::QuicForceBlockablePacketWriter> writer_;
61+ Network::ConnectionSocketPtr socket_;
62+ Event::Dispatcher& dispatcher_;
63+ };
64+
65+ void EnvoyQuicClientConnection::EnvoyQuicClinetPathContextFactory::CreatePathValidationContext (
66+ quic::QuicNetworkHandle network, quic::QuicSocketAddress peer_address,
67+ std::unique_ptr<quic::QuicPathContextFactory::CreationResultDelegate> result_delegate) {
68+ Network::Address::InstanceConstSharedPtr new_local_address;
69+ if (network == quic::kInvalidNetworkHandle ) {
70+ // If there isn't a meaningful network handle to bind to, bind to the
71+ // local address of the current socket.
72+ Network::Address::InstanceConstSharedPtr current_local_address =
73+ connection_.connectionSocket ()->connectionInfoProvider ().localAddress ();
74+ if (current_local_address->ip ()->version () == Network::Address::IpVersion::v4) {
75+ new_local_address = std::make_shared<Network::Address::Ipv4Instance>(
76+ current_local_address->ip ()->addressAsString (),
77+ ¤t_local_address->socketInterface ());
78+ } else {
79+ new_local_address = std::make_shared<Network::Address::Ipv6Instance>(
80+ current_local_address->ip ()->addressAsString (),
81+ ¤t_local_address->socketInterface ());
82+ }
83+ }
84+ Network::Address::InstanceConstSharedPtr remote_address =
85+ (connection_.peer_address () == peer_address)
86+ ? connection_.connectionSocket ()->connectionInfoProvider ().remoteAddress ()
87+ : quicAddressToEnvoyAddressInstance (peer_address);
88+ // new_local_address will be re-assigned if it is nullptr.
89+ QuicClientPacketWriterFactory::CreationResult result =
90+ writer_factory_.createSocketAndQuicPacketWriter (remote_address, network, new_local_address,
91+ connection_.connectionSocket ()->options ());
92+ connection_.setUpConnectionSocket (*result.socket_ , connection_.delegate_ );
93+ result_delegate->OnCreationSucceeded (std::make_unique<EnvoyQuicClientPathValidationContext>(
94+ envoyIpAddressToQuicSocketAddress (new_local_address->ip ()), peer_address, network,
95+ std::move (result.writer_ ), std::move (result.socket_ ), connection_.dispatcher_ ));
96+ }
97+
98+ quic::QuicNetworkHandle EnvoyQuicClientConnection::EnvoyQuicMigrationHelper::FindAlternateNetwork (
99+ quic::QuicNetworkHandle /* network*/ ) {
100+ return quic::kInvalidNetworkHandle ;
101+ }
102+
103+ quic::QuicNetworkHandle EnvoyQuicClientConnection::EnvoyQuicMigrationHelper::GetDefaultNetwork () {
104+ return quic::kInvalidNetworkHandle ;
105+ }
106+
107+ void EnvoyQuicClientConnection::EnvoyQuicMigrationHelper::OnMigrationToPathDone (
108+ std::unique_ptr<quic::QuicClientPathValidationContext> context, bool success) {
109+ if (success) {
110+ auto * envoy_context = static_cast <EnvoyQuicClientPathValidationContext*>(context.get ());
111+ // Connection already owns the writer.
112+ envoy_context->releaseWriter ();
113+ ++connection_.num_socket_switches_ ;
114+ connection_.setConnectionSocket (envoy_context->releaseSocket ());
115+ // Previous writer may have been force blocked and write events on it may have been dropped.
116+ // Synthesize a write event in case this case to unblock the connection.
117+ connection_.connectionSocket ()->ioHandle ().activateFileEvents (Event::FileReadyType::Write);
118+ // Send something to notify the peer of the address change immediately.
119+ connection_.SendPing ();
120+ }
121+ }
122+
123+ std::unique_ptr<quic::QuicPathContextFactory>
124+ EnvoyQuicClientConnection::EnvoyQuicMigrationHelper::CreateQuicPathContextFactory () {
125+ return std::make_unique<EnvoyQuicClinetPathContextFactory>(writer_factory_, connection_);
126+ }
50127
51128EnvoyQuicClientConnection::EnvoyQuicClientConnection (
52129 const quic::QuicConnectionId& server_connection_id, quic::QuicConnectionHelperInterface& helper,
@@ -153,8 +230,12 @@ void EnvoyQuicClientConnection::switchConnectionSocket(
153230}
154231
155232void EnvoyQuicClientConnection::OnPathDegradingDetected () {
233+ // This will trigger connection migration or port migration in QUICHE if
234+ // migration_helper_ is initialized. Otherwise do it in this class.
156235 QuicConnection::OnPathDegradingDetected ();
157- maybeMigratePort ();
236+ if (migration_helper_ == nullptr ) {
237+ maybeMigratePort ();
238+ }
158239}
159240
160241void EnvoyQuicClientConnection::maybeMigratePort () {
@@ -181,18 +262,20 @@ void EnvoyQuicClientConnection::probeWithNewPort(const quic::QuicSocketAddress&
181262 }
182263
183264 // The probing socket will have the same host but a different port.
184- auto probing_socket = createConnectionSocket (
185- peer_addr == peer_address () ? connectionSocket ()->connectionInfoProvider ().remoteAddress ()
186- : quicAddressToEnvoyAddressInstance (peer_addr),
187- new_local_address, connectionSocket ()->options ());
188- setUpConnectionSocket (*probing_socket, delegate_);
189- auto writer = std::make_unique<EnvoyQuicPacketWriter>(
190- std::make_unique<Network::UdpDefaultWriter>(probing_socket->ioHandle ()));
265+ ASSERT (migration_helper_ == nullptr && writer_factory_.has_value ());
266+ QuicClientPacketWriterFactory::CreationResult creation_result =
267+ writer_factory_->createSocketAndQuicPacketWriter (
268+ (peer_addr == peer_address ()
269+ ? connectionSocket ()->connectionInfoProvider ().remoteAddress ()
270+ : quicAddressToEnvoyAddressInstance (peer_addr)),
271+ quic::kInvalidNetworkHandle , new_local_address, connectionSocket ()->options ());
272+ setUpConnectionSocket (*creation_result.socket_ , delegate_);
273+ auto writer = std::move (creation_result.writer_ );
191274 quic::QuicSocketAddress self_address = envoyIpAddressToQuicSocketAddress (
192- probing_socket ->connectionInfoProvider ().localAddress ()->ip ());
275+ creation_result. socket_ ->connectionInfoProvider ().localAddress ()->ip ());
193276
194277 auto context = std::make_unique<EnvoyQuicPathValidationContext>(
195- self_address, peer_addr, std::move (writer), std::move (probing_socket ));
278+ self_address, peer_addr, std::move (writer), std::move (creation_result. socket_ ));
196279 ValidatePath (std::move (context), std::make_unique<EnvoyPathValidationResultDelegate>(*this ),
197280 reason);
198281}
@@ -241,15 +324,21 @@ void EnvoyQuicClientConnection::onFileEvent(uint32_t events,
241324 ASSERT (events & (Event::FileReadyType::Read | Event::FileReadyType::Write));
242325
243326 if (events & Event::FileReadyType::Write) {
244- OnBlockedWriterCanWrite ();
327+ writer ()->SetWritable ();
328+ // The writer might still be force blocked for migration in progress, in
329+ // which case no write should be attempted.
330+ WriteIfNotBlocked ();
245331 }
246332
247- bool is_probing_socket =
333+ // Check if the event is on the probing socket before read.
334+ const bool is_probing_socket =
248335 HasPendingPathValidation () &&
249336 (&connection_socket ==
250- &static_cast <EnvoyQuicClientConnection::EnvoyQuicPathValidationContext*>(
251- GetPathValidationContext ())
252- ->probingSocket ());
337+ (writer_factory_
338+ ? &static_cast <EnvoyQuicPathValidationContext*>(GetPathValidationContext ())
339+ ->probingSocket ()
340+ : &static_cast <EnvoyQuicClientPathValidationContext*>(GetPathValidationContext ())
341+ ->probingSocket ()));
253342
254343 // It's possible for a write event callback to close the connection, in such case ignore read
255344 // event processing.
@@ -331,8 +420,19 @@ void EnvoyQuicClientConnection::OnCanWrite() {
331420 onWriteEventDone ();
332421}
333422
423+ EnvoyQuicClientConnection::EnvoyQuicMigrationHelper&
424+ EnvoyQuicClientConnection::getOrCreateMigrationHelper (
425+ QuicClientPacketWriterFactory& writer_factory,
426+ OptRef<EnvoyQuicNetworkObserverRegistry> registry) {
427+ if (migration_helper_ == nullptr ) {
428+ migration_helper_ = std::make_unique<EnvoyQuicMigrationHelper>(*this , registry, writer_factory);
429+ }
430+ return *migration_helper_;
431+ }
432+
334433void EnvoyQuicClientConnection::probeAndMigrateToServerPreferredAddress (
335434 const quic::QuicSocketAddress& server_preferred_address) {
435+ ASSERT (migration_helper_ == nullptr );
336436 probeWithNewPort (server_preferred_address,
337437 quic::PathValidationReason::kServerPreferredAddressMigration );
338438}
0 commit comments